using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WeChatWASM;
using System;
using Sirenix.OdinInspector;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.IO;
using System.Linq;
using UnityEngine.Networking;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using M0;
using Newtonsoft.Json;
using UnityEngine.Events;
using SystemInfo = WeChatWASM.SystemInfo;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
using Sirenix.OdinInspector.Editor;
#endif

#if 微信小游戏
#region 类声明
public enum 开关
{
    开,
    关,
}
public enum 语言
{
    英文,
    简中,
    繁中,
}
public enum 语言Type
{
    en,
    zh_CN,
    zh_TW,
}
public enum 性别
{
    未知,
    男,
    女,
}
public enum 对齐方式
{
    左,
    中,
    右,
}
public enum 屏幕朝向
{
    竖屏,
    横屏,
}
public enum 按钮类型
{
    文本按钮,
    图片按钮,
}
public enum 游戏圈图标样式
{
    黑标,
    白标,
    绿标,
    白底绿标,
}
public enum 分享图片
{
    Icon,
    截图,
    审核图,
}
public enum 录屏状态
{
    未开启,
    录制中,
    暂停,
}
public enum 客户端平台
{
    [LabelText("IOS", Icon = SdfIconType.Apple)] IOS,
    [LabelText("Android", Icon = SdfIconType.Google)] Android,
    [LabelText("Windows", Icon = SdfIconType.Windows)] Windows,
    [LabelText("Mac", Icon = SdfIconType.Apple)] Mac,
    [LabelText("Devtools", Icon = SdfIconType.Wrench)] Devtools,
}
public enum 系统主题
{
    浅色,
    深色,
}
public enum 字体方案
{
    微信字体,
    自定义字体,
}
public enum 采用字体方案
{
    预配置,
    后追配,
}

public enum 自定义字体枚举
{
    无,
    微信字体,
    自定义字体1,
    自定义字体2,
}
[Serializable]
public class 分享Config
{
    public string type;
    public List<string> sTitle;
    public List<string> sId;
    public List<string> sUrl;
    public int Param1;
}

[Serializable]
public class 自定义字体配置
{
    public 自定义字体枚举 Type;
    public string 下载地址;
    public bool 预加载;
}

[Serializable] public class 审核图片
{
    [Required("请输编号。")]
    [HorizontalGroup(0.3f), LabelWidth(30)] public string 编号;
    [Required("请输入图片地址。")]
    [HorizontalGroup, LabelWidth(30)] public string 地址;
}
[Serializable] public class 广告设置
{
    [TableColumnWidth(60, Resizable = false),ReadOnly] public string 名称;
    [TableColumnWidth(20, Resizable = false)]public bool 启;
    [EnableIf("启"), GUIColor("@ID.Length>0?Color.white:Color.red")] public string ID;
    public WXCustomAd 模板广告;
    public WXBannerAd Banner广告;
}
// [Serializable] public class 开放数据域通信
// {
//     // type 用于表明消息类型
//     // 需与open-data里约定一致
//     public string type;
//     public string shareTicket;
//     public int score;
//
//     // 静态方法为了使用方便
//     public static 开放数据域通信 展示好友排行榜()
//     {
//         开放数据域通信 message = new 开放数据域通信();
//         message.type = "showFriendsRank";
//         return message;
//     }
//     public static 开放数据域通信 展示群组排行榜(string 群分享对应的标识)
//     {
//         开放数据域通信 message = new 开放数据域通信();
//         message.type = "showGroupFriendsRank";
//         message.shareTicket = 群分享对应的标识;
//         return message;
//     }
//
//     public static 开放数据域通信 设置用户记录(int 分数)
//     {
//         开放数据域通信 message = new 开放数据域通信();
//         message.type = "setUserRecord";
//         message.score = 分数;
//         return message;
//     }
//     
//     // public class 云端唯一ID回调结果
//     // {
//     //     public bool 成功回调;
//     //     public string Content;
//     //     public string Content;
//     // }
// }


[Serializable]
public class GetOpenId
{
    public string session_key;
    public string openid;
    public bool Result;
    public string errcode;
    public string errmsg;
}

#endregion

public class WeiChatSDK : MonoBehaviour
{
    public static WeiChatSDK Instance
    {
        get { return 微信SDK; }
    }
    public static WeiChatSDK 微信SDK;
    private void Awake()
    {
        if (微信SDK == null)
        {
            init();
        }
        else
        {
            Destroy(gameObject); // 如果已经存在其他实例，则销毁当前实例
        }
       
    }

    void init()
    {
        if (指定模式 == 开关.开)
        {
            MyEvent.Instance.SetEvent<string>("Get游戏模式", () => { return 模式.ToString();});
        }
        else
        {
            var info = WX.GetAccountInfoSync();
            var 自动模式 = 已注册的模式.微信小游戏;
#if UNITY_EDITOR
            自动模式 = 已注册的模式.编辑器开发;
#else
             if (info != null && info.miniProgram != null &&
                !string.IsNullOrEmpty(info.miniProgram.envVersion))
             {
                 if (info.miniProgram.envVersion == "develop" || info.miniProgram.envVersion == "trial")
                 {
                     自动模式 = 已注册的模式.微信小游戏体验版;
                     发送消息("进入：微信小游戏体验版!!!!!!!!!!");
                 }
                 else
                 {
                     自动模式 = 已注册的模式.微信小游戏;
                     发送消息("进入：微信小游戏!!!!!!!!!!!!!!!!!");
                 }
             }
             else
             {
                 自动模式 = 已注册的模式.微信小游戏;
                 发送消息("进入：微信小游戏,排除法！！！！！！！！！！！",1);
             }
#endif
            MyEvent.Instance.SetEvent<string>("Get游戏模式", () => { return 自动模式.ToString();});
        }
        
        微信SDK = this; // 将当前实例赋值给全局控制变量
        DontDestroyOnLoad(gameObject);
        
        WX.InitSDK((code) =>
        {
            微信初始化();
        });
    }


    public void 上报错误(string s)
    {
        Dictionary<string, string> p = new Dictionary<string, string>();
        //$p,$Id,$Vesion
        p.Add("Id",用户OpenID);
        p.Add("p",s);
        string v = MyEvent.Instance.DoFuncEvent<string>("获得版本号");
        p.Add("Vesion",v);

#if UNITY_EDITOR
        Debug.Log(" 来自unity 上报数据"+JsonConvert.SerializeObject(p));
#else
        服务器.Instance.Post接口_无回调("CatchError", p, false, false);
#endif
        
    }
    
    #region 向基类报告

    [Flags]
    public enum 已注册的模式
    {
        编辑器开发 = 1,
        微信小游戏 = 2,
        微信小游戏体验版 = 4,
        // all = 0&1&2,
    }
    
    [BoxGroup("基类设置")]  public 开关 指定模式;
    [BoxGroup("基类设置"),ShowIf("@指定模式 == 开关.开"), EnumToggleButtons ] public 已注册的模式 模式;

     #endregion


    
    private async void 微信初始化()
    {
        // 微信登入();
        尝试获取头像();
        补充广告();
        SDK初始化 = true;
        发送消息("【初始化】微信SDK初始化完成");

        if (字体功能 == 开关.开)
        {
            await  预加载字体配置((f)=>{Debug.Log($"字体加载进度:{f}");});
        }
        
    }

    // private string 登入返回code;
    private void 微信登入(Action<string> callBack)
    {
        WX.Login(new LoginOption()
        {
            success = (c) =>
            {
                callBack?.Invoke(c.code);
            },
            // fail = (f)=>{BDebug.Error("登入失败：："+f.errMsg);}
        });
    }


    #region 从云端获得OPenID和秘钥

    /// <summary>
    /// string :url
    /// action<string> 回调
    /// </summary>

    public void Get会话秘钥(Action<string> 获得秘钥回调)
    {
        if (string.IsNullOrEmpty(会话秘钥))
        {
            发送消息("会话秘钥为空，尝试登入");
            微信登入((code) =>
            {
                申请唯一ID和秘钥(code, (成功,data) =>
                {
                    if (成功)
                    {
                        获得秘钥回调?.Invoke(会话秘钥);
                    }
                });
            });
            return;
        }
        
        //检查缓存的秘钥是否过期
        WX.CheckSession(new CheckSessionOption //检测登录状态并登录
        {
            fail = (error) =>
            {
                // session_key 已经失效，需要重新执行登录流程
                发送消息("登录失效，即将重新登录。", 1);
                会话秘钥 = null;
                Get会话秘钥(获得秘钥回调);
            },
            success = (o) =>
            {
                获得秘钥回调?.Invoke(会话秘钥);
            }
        });
    }
    
    public void Get唯一ID(Action<string> 获得唯一ID回调)
    {
        if (string.IsNullOrEmpty(用户OpenID))
        {
            微信登入(code =>
            {
                申请唯一ID和秘钥(code, (成功,data) =>
                {
                    if (成功)
                    {
                        获得唯一ID回调?.Invoke(用户OpenID);
                    }
                });
            });
        }
        else
        {
            获得唯一ID回调?.Invoke(会话秘钥);
        }
    }

    private void 申请唯一ID和秘钥(string code,Action<bool,GetOpenId> 申请回调)
    {
        // // var server = 服务器.Instance;
        // var url =$"{server.Get网址}/index.php/{获得OpenIdUrl}";
        // Dictionary<string, string> 参数 = new Dictionary<string, string>();
        // 参数.Add("appid",Appid);
        // 参数.Add("secret",Appsecret);
        // 参数.Add("js_code",code);
        // server.Post完整网站<GetOpenId>(url,参数, (data) =>
        // {
        //     if (!data.errmsg.NullOrEmpty())
        //     {
        //         // BDebug.Error("申请ID遇到报错：："+data.errcode+" "+data.errmsg);
        //         申请回调?.Invoke(false,data);
        //     }
        //     else
        //     {
        //         会话秘钥 = data.session_key;
        //         用户OpenID = data.openid;
        //         发送消息("获取到的session_key：" + 会话秘钥);
        //         发送消息("获取到的openid：" + 用户OpenID);
        //         申请回调?.Invoke(true,data);
        //     }
        // }, () => { Debug.LogError("申请唯一ID失败");},false,false);
        // // string 连接 = $"https://api.weixin.qq.com/sns/jscode2session?appid={Appid}&secret={Appsecret}&js_code={code}&grant_type=authorization_code";
    }

    
    #endregion

    
#region 全局设置
    #if UNITY_EDITOR
    [BoxGroup("全局设置/调试"), Button(ButtonSizes.Medium,Icon = SdfIconType.Globe2), GUIColor(0, 1, 0),ShowInInspector]private void 使用指南()
    {
        Application.OpenURL("https://cgobsidian.feishu.cn/wiki/I81GwiJIBiyTJ2kikuucT2nTnNy");                  // 使用默认浏览器打开指定的URL
    }
#endif
    [InfoBox("需要获取用户敏感资料时，Appid和Appsecret不能为空！", "@string.IsNullOrEmpty(Appid)||string.IsNullOrEmpty(Appsecret)")]
    [BoxGroup("全局设置"), ShowIf("@敏感资料 == 开关.开")   , GUIColor("@string.IsNullOrEmpty(Appid)||string.IsNullOrEmpty(Appsecret)?Color.red:Color.white")]              public string Appid;
    [BoxGroup("全局设置"), ShowIf("@敏感资料 == 开关.开")  , GUIColor("@string.IsNullOrEmpty(Appid)||string.IsNullOrEmpty(Appsecret)?Color.red:Color.white")]               public string Appsecret;
    [BoxGroup("全局设置"), ShowIf("@敏感资料 == 开关.开")  , GUIColor("@string.IsNullOrEmpty(获得OpenIdUrl)?Color.red:Color.white")]               public string 获得OpenIdUrl="weichat/index/GetOpenId";
    
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/1"), EnumToggleButtons, LabelText("用户信息")]                                                               public 开关 用户信息授权功能    = 开关.关;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/1"), EnumToggleButtons, LabelText("获得唯一ID")]                      public 开关 敏感资料            = 开关.关;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/2"), EnumToggleButtons, LabelText("字体")]                                                                   public 开关 字体功能            = 开关.开;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/2"), EnumToggleButtons, LabelText("录屏")    ,ReadOnly ]                                                     public 开关 录屏功能            = 开关.关;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/3"), EnumToggleButtons, LabelText("广告")]                                                                   public 开关 广告功能            = 开关.开;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/3"), EnumToggleButtons, LabelText("分享")]                                                                   public 开关 分享功能            = 开关.开;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/4"), EnumToggleButtons, LabelText("游戏圈")]                                                                 public 开关 游戏圈功能          = 开关.开;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/4"), EnumToggleButtons, LabelText("排行榜")]                                                                 public 开关 排行榜功能          = 开关.开;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/5"), EnumToggleButtons, LabelText("客服")    , ReadOnly]                                                     public 开关 客服功能            = 开关.关;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/5"), EnumToggleButtons, LabelText("订阅")    , ReadOnly]                                                     public 开关 订阅功能            = 开关.关;
    [BoxGroup("全局设置/功能"), HorizontalGroup("全局设置/功能/6"), EnumToggleButtons, LabelText("调试信息"),LabelWidth(60)]                                                public 开关 调试信息            = 开关.关;
    private Action 场景切换事件 = () => { };
    private Action 刷新 = () => { };
    
    #region 广告或分享
    /// <summary>
    /// 如果本次累计分享次数>=必定分享次数,则根据权重随机获取，否则必定分享。
    /// 返回 true = 广告，
    /// 返回 false = 分享。
    /// </summary>
    /// <returns></returns>
    public bool 广告或分享()
    {
        if (本次累计分享次数 >= 必定分享次数)
        {
            return UnityEngine.Random.Range(1, 100) > 广告比重 ? false : true;
        }
        else
        {
            return false;
        }
    }
    #endregion

    #region 申请授权
    /// <summary>
    /// scope.userInfo = 用户信息（文案说无法使用，需要使用创建用户授权信息按钮才行，但是直接提出申请也行。）
    /// scope.userFuzzyLocation = 模糊地理位置，
    /// scope.werun = 微信运动步数，
    /// scope.writePhotosAlbum = 保存到相册，
    /// scope.WxFriendInteraction = 好友信息，
    /// scope.gameClubData = 游戏圈，
    /// </summary>
    public void 申请授权(string 授权内容, Action 成功操作, Action 失败操作)
    {
        //判断是否已经授权
        bool 已授权 = false;
        WX.GetSetting(new GetSettingOption()
        {
            success = (成功) =>
            {
                已授权 = true;
                发送消息($"授权信息{JsonConvert.SerializeObject(成功)}");
                if (!成功.authSetting.ContainsKey(授权内容) || !成功.authSetting[授权内容])          //授权失败再申请
                {
                    申请用户信息授权(授权内容, 成功操作, 失败操作);
                }
                else
                {
                    成功操作();  //已经授权
                }
            },
        });
        // if (!已授权) //处理GetSetting失败的情况，未授权前无法获得scope.userInfo的信息。
        // {
        //      失败操作();
        // }
    }

    public void 申请用户信息授权(string 授权内容, Action 成功操作, Action 失败操作)
    {
        WX.Authorize(new AuthorizeOption()    //申请授权.
        {
            scope = 授权内容,
            success = (成功) =>
            {
                成功操作();
                发送消息($"授权成功");
            },
            fail = (失败) =>
            {
                失败操作();
                // 微信提示消息(失败提示, "error", true, 3000);
            },
        });
    }
    #endregion

    #region 微信提示消息
    /// <summary>
    /// 文字内容限制7字
    /// 图标：success - 成功 , error - 错误 , loading - 加载 , none - 无图标
    /// </summary>
    /// <param name="内容"></param>
    public void 微信提示消息(string 内容, string 图标, bool 遮罩, int 延迟时长 = 1500)
    {
        WX.ShowToast(new ShowToastOption()  //显示消息提示框
        {
            title = 内容,
            icon = 图标,
            duration = 延迟时长,
            mask = 遮罩,
        });
    }
    #endregion

    #region 调试信息
    /// <summary>
    /// 类型 :0=正常，1=警示，2=错误
    /// </summary>
    /// <param name="内容"></param>
    /// <param name="类型"></param>
    public void 发送消息(string 内容, int 类型 = 0)
    {
        if (调试信息 == 开关.关) return;
        switch (类型)
        {
            case 0:
                Debug.Log(内容);
                break;
            case 1:
                Debug.LogWarning(内容);
                break;
            case 2:
                Debug.LogError(内容);
                break;
        }
    }
    #endregion



    #region 局部方法汇集

#if UNITY_EDITOR
    void 检测名称(string 名称)
    {
        foreach (EditorBuildSettingsScene 构建场景 in EditorBuildSettings.scenes)                // 将 Build Settings 中包含的场景路径存储在列表中
        {
            Scene 场景 = EditorSceneManager.OpenScene(构建场景.path, OpenSceneMode.Additive);    // 打开场景
            if (场景.isLoaded)                                                                   // 如果场景已加载
            {
                GameObject[] 根物体 = 场景.GetRootGameObjects();
                foreach (var 当前物 in 根物体)
                {
                    检测子物体名称(当前物, 名称, 场景.name);
                }
                EditorSceneManager.CloseScene(场景, true);         // 关闭场景
            }
        }
    }
    void 检测子物体名称(GameObject 父物体, string 名称, string 场景名)
    {
        if (父物体.name == 名称)
        {
            Debug.Log($"场景：{场景名} 物品：{父物体.name}");
        }

        foreach (Transform 子物体 in 父物体.transform)
        {
            检测子物体名称(子物体.gameObject, 名称, 场景名);
        }
    }
#endif
    Rect 获取按钮位置大小(RectTransform 组件)
    {
        Vector3[] 四边角 = new Vector3[4];
        组件.GetWorldCorners(四边角);                                        // 获取组件的四个角的世界坐标
        Vector3 左下 = Camera.main.WorldToScreenPoint(四边角[0]);            // 将左下角和右上角的世界坐标转换为屏幕坐标
        Vector3 右上 = Camera.main.WorldToScreenPoint(四边角[2]);
        float 屏幕高度 = Screen.height;                                      // 因为Unity屏幕坐标的原点在左下角，而GUI的坐标原点在左上角，所以需要对Y坐标进行转换
        左下.y = 屏幕高度 - 左下.y;
        右上.y = 屏幕高度 - 右上.y;
        return new Rect(左下.x, 右上.y, 右上.x - 左下.x, 左下.y - 右上.y);
    }
    
    /// <summary>
    /// 排行榜
    /// </summary>
    /// <param name="rect"></param>
    /// <returns></returns>
    public  (int, int, int, int) Get微信Rect转化坐标( RectTransform rect)
    {
        CanvasScaler scaler = GameObject.FindWithTag("Canvas").GetComponent<CanvasScaler>();
        var referenceResolution = scaler.referenceResolution;
        // rect.pivot = new Vector2(0, 0);
        var p = rect.transform.position;

        int x = (int) p.x;
        int y = Screen.height - (int)p.y;
        int width = (int) ((Screen.width / referenceResolution.x) * rect.rect.width);
        int height = (int) ((Screen.width / referenceResolution.x) * rect.rect.height);
        
        Debug.Log("Get微信Rect转化坐标============");
        Debug.Log(x);
        Debug.Log(y);
        Debug.Log(width);
        Debug.Log(height);

        
        return (x, y, width, height);
    }
    
    //
    public static (int, int, int, int) GetWxButtonRect(RectTransform 工具人)
    {
        var rect = ChangeToRect(工具人);
        return GetWxButtonRect(rect);
    }
    /// <summary>
    /// 转化成微信按钮范围
    /// </summary>
    /// <returns> x,y,width,height</returns>
    public static Rect ChangeToRect(RectTransform 隐身工具人)
    {
        var 屏幕大小 = Get屏幕大小();
        var 画布大小 = screen分辨率Size;
        Debug.Log(屏幕大小);
        Debug.Log(画布大小);
        
        Vector3[] 四边角 = new Vector3[4];
        隐身工具人.GetWorldCorners(四边角);                                        // 获取组件的四个角的世界坐标

        Vector2 v2左下;
        Vector2 v2右上;
        var camera = GameObject.FindWithTag("Camera");
        if (camera != null)
        {
            var CameraMain = camera.GetComponent<Camera>();
            if (CameraMain != null)
            {
                Vector3 左下 = CameraMain.WorldToScreenPoint(四边角[0]);            // 将左下角和右上角的世界坐标转换为屏幕坐标
                Vector3 右上 = CameraMain.WorldToScreenPoint(四边角[2]);
                v2左下 = (Vector2)左下 - (画布大小 / 2);
                v2右上 = (Vector2)右上 - (画布大小 / 2);
            
                Debug.Log("四边角");
                Debug.Log(左下);
                Debug.Log(右上);
            }
            else
            {
                Vector3 左下 = 四边角[0];            // 将左下角和右上角的世界坐标转换为屏幕坐标
                Vector3 右上 = 四边角[2];
                v2左下 = (Vector2)左下 - (画布大小 / 2);
                v2右上 = (Vector2)右上 - (画布大小 / 2);
            
                Debug.Log("四边角");
                Debug.Log(左下);
                Debug.Log(右上);
            }
        }
        else
        {
            Vector3 左下 = 四边角[0];            // 将左下角和右上角的世界坐标转换为屏幕坐标
            Vector3 右上 = 四边角[2];
            v2左下 = (Vector2)左下 - (画布大小 / 2);
            v2右上 = (Vector2)右上 - (画布大小 / 2);
            
            Debug.Log("四边角");
            Debug.Log(左下);
            Debug.Log(右上);
        }
        
        

        float x = 画布大小.x/2f + v2左下.x;
        float y = 画布大小.y/2f - v2右上.y;
        float width = v2右上.x - v2左下.x;
        float height = v2右上.y - v2左下.y;
        
        return new Rect(x,y,width,height);
    }
    static WeChatWASM.SystemInfo Wx系统信息;
    public static (int, int, int, int) GetWxButtonRect(Rect rect)
    {
        if (Wx系统信息 == null)
        {
            Wx系统信息 = WX.GetSystemInfoSync();
        }

        float 像素比 = 1f;
        if (Wx系统信息 != null)
        {
            像素比 = (float)Wx系统信息.pixelRatio;
        }

        int x = (int)(rect.x / 像素比);
        int y = (int)(rect.y / 像素比);
        int width = (int)(rect.width / 像素比);
        int height = (int)(rect.height / 像素比);
        
        Debug.Log(像素比);
        Debug.Log("==============");
        Debug.Log(x);
        Debug.Log(y);
        Debug.Log(width);
        Debug.Log(height);
        
        return (x, y, width, height);
    }
    public static Vector2 Get屏幕大小()
    {
        var info = WeChatWASM.WX.GetSystemInfoSync();
        return new Vector2((float)info.screenWidth, (float)info.screenHeight);
    }
    static public Vector2 screen分辨率Size
    {
        get
        {
            return new Vector2(Screen.width,Screen.height); 
        }
    }
    
    

    #endregion
#endregion

#region 包体优化
    [BoxGroup("包体优化"), Button(ButtonSizes.Medium, Icon = SdfIconType.Globe2), GUIColor(0, 1, 0), ShowInInspector]
    private void 包体优化()
    {
        Application.OpenURL("https://cgobsidian.feishu.cn/wiki/I81GwiJIBiyTJ2kikuucT2nTnNy");                  // 使用默认浏览器打开指定的URL
    }
#endregion

#region 登录与用户授权功能

private const string 用户授权Key = "scope.userInfo";
private const string 好友授权Key = "scope.WxFriendInteraction";

    [InfoBox("省份等隐私不再获取", InfoMessageType.Warning, "@用户信息授权功能 == 开关.开")]
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"), LabelWidth(50), ReadOnly] private string 会话秘钥;
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("OpenID"), LabelWidth(50),ReadOnly] private string 用户OpenID;
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("头像URL"), LabelWidth(50), ReadOnly] public string 用户头像图片URL;
    // [BoxGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("头像"), LabelWidth(50), ReadOnly] public Sprite 用户头像图片;
    // [BoxGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("国家"), Tooltip("不再返还。"), HorizontalGroup("用户信息/地区", 0.3f), LabelWidth(50), ReadOnly] public string 用户国家;
    // [BoxGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("省份"), Tooltip("不再返还。"), HorizontalGroup("用户信息/地区"), LabelWidth(50), ReadOnly] public string 用户省份;
    // [BoxGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelText("城市"), Tooltip("不再返还。"), HorizontalGroup("用户信息/地区"), ReadOnly] public string 用户城市;
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),LabelWidth(50), ReadOnly] public string 昵称;
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),EnumToggleButtons, LabelWidth(50), ReadOnly] public 性别 性别;
    [FoldoutGroup("用户信息"), ShowIf("@用户信息授权功能 == 开关.开"),EnumToggleButtons, ReadOnly] public 语言 用户语言;

    

    void 登录执行(Action<bool,string> 登入执行回调)
    {
        发送消息("登录执行。");
        WX.Login(new LoginOption
        {
            timeout = 10000, // 超时时间，单位ms
            complete = (r)=>{},
            fail = (error) => {
                微信提示消息("登录失败请重试"+error.errMsg, "error", true, 3000);
                登入执行回调?.Invoke(false,"");
            },
            success = (result) => {
                登入执行回调?.Invoke(true,result.code);
            },
        });
    }


    // private IEnumerator 获取SessionKey和OpenId协程(string 代码, Action 回传事件)
    // {
    //     string 连接 = $"https://api.weixin.qq.com/sns/jscode2session?appid={Appid}&secret={Appsecret}&js_code={代码}&grant_type=authorization_code";
    //         
    //     using (UnityWebRequest 网络请求 = UnityWebRequest.Get(连接))
    //     {
    //         yield return 网络请求.SendWebRequest();
    //         
    //         if (网络请求.result != UnityWebRequest.Result.Success)
    //         {
    //             发送消息("网络请求错误: " + 网络请求.error, 2);
    //             GetOpenIdEvent?.Invoke("",false);
    //         }
    //         else
    //         {
    //             string 回复 = 网络请求.downloadHandler.text;
    //             var Json数据 = JsonUtility.FromJson<WeChatResponse>(回复);
    //             发送消息("获取到的session_key：" + Json数据.session_key);
    //             发送消息("获取到的openid：" + Json数据.openid);
    //             会话秘钥 = Json数据.session_key;
    //             用户OpenID = Json数据.openid;
    //             回传事件();
    //             GetOpenIdEvent?.Invoke(用户OpenID,true);
    //         }
    //     }
    // }

    #region 用户授权信息按钮刷新部分
    
    

    #endregion

    public void 尝试获取头像()
    {
        if (用户信息授权功能 == 开关.关)
        {
            return;
        }
        
        string 授权内容 = "scope.userInfo";
        WX.GetSetting(new GetSettingOption()
        {
            success = (成功) =>
            {
                发送消息($"授权信息{JsonConvert.SerializeObject(成功.authSetting)}");
                if (成功.authSetting.ContainsKey(授权内容) && 成功.authSetting[授权内容])          //授权失败再申请
                {
                    Debug.Log("授权成功，获取头像");
                    WX.GetUserInfo(new GetUserInfoOption
                    {
                        lang = 微信语言,
                        withCredentials = true,
                        complete = (res) => {
                            设置加载中状态(false);
                        },
                        fail = (失败) => {
                            Debug.Log("失败：："+失败.errMsg);
                            微信提示消息("用户信息授权失败请重试", "error", true);
                        },
                        success = (成功) =>
                        {
                            发送消息("用户信息新授权成功");
                            UserInfo 用户信息 = 成功.userInfo;
                            // 用户信息.nickName
                            昵称 = 用户信息.nickName;
                            用户头像图片URL = 用户信息.avatarUrl;
                            
                            // Get用户头像Event?.Invoke(昵称,用户头像图片URL,true);
                            MyEvent.Instance.DoEvent("Get用户头像Event", (昵称, 用户头像图片URL, true));
                        },
                    });
                }
                else
                {
                    Debug.Log("未授权，等待排行榜头像点击授权");
                }
            },
        });
    }
    
    /// <summary>
    /// 解密微信数据
    /// </summary>
    /// <param name="encryptedData">加密的数据</param>
    /// <param name="encryptIv">iv向量</param>
    /// <param name="sessionKey">调用 wx auth.code2Session 来获得</param>
    /// <returns></returns>
    public string 微信解密(string encryptedData, string encryptIv, string sessionKey)
    {
        发送消息($"开始解密");
        //base64解码为字节数组
        var 加密数据 = Convert.FromBase64String(encryptedData);
        var key = Convert.FromBase64String(sessionKey);
        var iv = Convert.FromBase64String(encryptIv);

        //创建aes对象
        var aes = Aes.Create();

        if (aes == null)
        {
            throw new InvalidOperationException("未能获取Aes算法实例");
        }
        //设置模式为CBC
        aes.Mode = CipherMode.CBC;
        //设置Key大小
        aes.KeySize = 128;
        //设置填充
        aes.Padding = PaddingMode.PKCS7;
        aes.Key = key;
        aes.IV = iv;

        //创建解密器
        var de = aes.CreateDecryptor();
        //解密数据
        var decodeByteData = de.TransformFinalBlock(加密数据, 0, 加密数据.Length);
        //转换为字符串
        var data = Encoding.UTF8.GetString(decodeByteData);
        发送消息($"解密：{data}");
        return data;
    }

    public string 微信解密(string encryptedData, string encryptIv)
    {
        if (string.IsNullOrEmpty(会话秘钥))
        {
            return "";
        }
        return 微信解密(encryptedData,encryptIv,会话秘钥);
    }
    void 图片加载(string 地址)
    {
        // StartCoroutine(LoadImage(地址));
    }

    // private IEnumerator LoadImage(string 地址)
    // {
    //     UnityWebRequest www = UnityWebRequestTexture.GetTexture(地址);
    //     var asyncOperation = www.SendWebRequest();
    //
    //     while (!asyncOperation.isDone)
    //     {
    //         yield return null;
    //     }
    //
    //     if (www.result != UnityWebRequest.Result.Success)
    //     {
    //         Debug.LogError("Failed to load image: " + www.error);
    //     }
    //     else
    //     {
    //         Texture2D texture = DownloadHandlerTexture.GetContent(www);
    //         Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);
    //         用户头像图片 = sprite;
    //         xxxxx.sprite = sprite;
    //     }
    // }

    #endregion

#region 字体功能

    [FoldoutGroup("字体功能"),ShowIf("@字体功能 == 开关.开"), EnumToggleButtons, ReadOnly] public 采用字体方案 采用字体方案  = 采用字体方案.预配置;
#if UNITY_EDITOR
    [Button(ButtonSizes.Medium,Icon = SdfIconType.Window), GUIColor(0, 1, 0), BoxGroup("字体功能/设置",showLabel:false), ShowIf("@字体功能 == 开关.开")]public void 打开字体预配置窗口()
    {
        FontSettingsWindows 字体配置窗口 = (FontSettingsWindows)EditorWindow.GetWindow(typeof(FontSettingsWindows));
        GUIContent titleContent = new GUIContent();
        titleContent.text = "字体配置窗口";
        字体配置窗口.titleContent = titleContent;
        字体配置窗口.Show();
    }
#endif
    //自定义字体功能未完成，暂时无法使用。  问题：微信文件管理与Unity文件不互通，下载的Font文件无法被加载。
    [FoldoutGroup("字体功能"), ShowIf("@字体功能 == 开关.开"), EnumToggleButtons] public bool 配置自定义字体;
    [FoldoutGroup("字体功能"), ShowIf("@字体功能 == 开关.开&&配置自定义字体"), EnumToggleButtons] public List<自定义字体配置> 自定义字体配置s;
    [FoldoutGroup("字体功能"), ShowIf("@字体功能 == 开关.开"), EnumToggleButtons] public 开关 移出工程字体;
    
    [FoldoutGroup("字体功能"),InlineButton("@Set项目隐藏文件夹()", Label = "@隐藏字体文件夹 == 开关.关?\"当前关\":\"当前开\"", Icon = SdfIconType.Alt)]
    [Required]
    [FoldoutGroup("字体功能"),InfoBox("移出工程字体,可以将所有字体集中可隐藏文件夹，导出时一键隐藏文件夹"),ShowIf("@字体功能 == 开关.开 && 移出工程字体==开关.开")] public string 隐藏文件夹路径;
    [HideInInspector]public 开关 隐藏字体文件夹 = 开关.关;
    // [InfoBox("1、功能适配范围【<color=red>画布内</color>】和【<color=red>本代码内</color>】的子对象字体。" +
    //     "\n2、采用微信或自定义字体,【<color=red>打包前需先执行移除项目文字</color>】。" +
    //     "\n3、【<color=red>Default Font Asset 设置为空</color>】\n       Project Settings - TextMesh Pro - Settings " +
    //     "\n4、观察字体打包时不会携带，无需清除。", InfoMessageType.Warning, "@字体功能 == 开关.开")]
    [FoldoutGroup("字体功能"), ShowIf("@字体功能 == 开关.开"), LabelText("微信字体失败返回字体下载地址",Icon = SdfIconType.Globe2), TextArea(2, 4)] public string 失败返回字体 = "https://zf.sc.chinaz.com/Files/DownLoad/upload/2023/0818/lianxiangxiaoxinheitichanggui.ttf"; //联想小新黑体常规 https://font.chinaz.com/23081920972.htm

    [FoldoutGroup("字体功能"), ShowIf("@字体功能 == 开关.开"),EnumToggleButtons] public 开关 使用材质球;
    [Required("请配置材质球")]
    [FoldoutGroup("字体功能/字体材质"), ShowIf("@字体功能 == 开关.开 && 使用材质球 == 开关.开")] public Material 文字材质球;
    [FoldoutGroup("字体功能/字体材质"), HorizontalGroup("字体功能/字体材质/1"), ShowIf("@字体功能 == 开关.开&&使用材质球 == 开关.开"), Range(-1, 1)] public float 字体膨胀;
    [FoldoutGroup("字体功能/字体材质"), HorizontalGroup("字体功能/字体材质/1"), ShowIf("@字体功能 == 开关.开&&使用材质球 == 开关.开"), Range(0, 1)] public float 字体描边;
    // [HideInInspector] public TMP_FontAsset 采用文字;
    // private TMP_FontAsset 自定义字体文件;
    // private TMP_FontAsset 微信字体文件;
    // private Font 下载字体Font文件;
    // private bool 字体首次加载完毕;
    // private int 文本组件数量;

    public void Set项目隐藏文件夹()
    {
        if (string.IsNullOrEmpty(隐藏文件夹路径))
        {
            return;
        }
#if UNITY_EDITOR
        隐藏文件夹路径 = 隐藏文件夹路径.Replace("\\", "/").Replace(".","");
        var allN = 隐藏文件夹路径.Split('/');
        string name = allN.Last();

        string p隐藏 = "";
        allN[allN.Length - 1] = "." + allN[allN.Length - 1];
                
        foreach (var VARIABLE in allN)
        {
            p隐藏 =p隐藏+ VARIABLE + "/";
        }
        p隐藏 = p隐藏.Substring(0, p隐藏.Length - 1);
        string p开 = p隐藏.Replace(".","");

        if (隐藏字体文件夹 == 开关.关)
        {
            隐藏字体文件夹 = 开关.开;
            if (!Directory.Exists(p隐藏))
            {
                return;
            }
                
            var 隐藏meta路径 = p隐藏 + ".meta";
            File.Delete(隐藏meta路径);
            var 开路径 = p隐藏.Replace(".", "");

            Directory.CreateDirectory(开路径);
            // var 
            foreach (var VARIABLE in new DirectoryInfo(p隐藏).GetFiles())
            {
                var n = VARIABLE.Name;
                var p = 开路径 +"/"+ n;
                File.Copy(VARIABLE.FullName,p,true);
                File.Delete(VARIABLE.FullName);
            }
            // File.Copy(p隐藏,开路径,true);
            // foreach (var VARIABLE in COLLECTION)
            // {
            //     
            // }
            Directory.Delete(p隐藏);
            EditorUtility.SetDirty(this);
            AssetDatabase.Refresh();
        }
        else
        {
            隐藏字体文件夹 = 开关.关;
            if (!Directory.Exists(p开))
            {
                return;
            }
            var 隐藏meta路径 = p开 + ".meta";
            File.Delete(隐藏meta路径);
            
            Directory.CreateDirectory(p隐藏);
            foreach (var VARIABLE in new DirectoryInfo(p开).GetFiles())
            {
                var n = VARIABLE.Name;
                var p = p隐藏 +"/"+ n;
                File.Copy(VARIABLE.FullName,p,true);
                File.Delete(VARIABLE.FullName);
            }
            // File.Copy(p开,p隐藏,true);
            Directory.Delete(p开);
            EditorUtility.SetDirty(this);
            AssetDatabase.Refresh();
        }
#endif
        
    }

    
    /// <summary>
    /// 预加载字体
    /// </summary>
    private async Task 预加载字体配置(Action<float> 总进度Call)
    {
        if (字体功能 == 开关.开)
        {
            int 预加载数量 = 自定义字体配置s.Where(w => w.预加载).Count();
            List<float> 字体进度 = new List<float>();
            for (int i = 0; i < 预加载数量; i++)
            {
                字体进度.Add(0f);
            }
            int index = 0;

            foreach (var VARIABLE in 自定义字体配置s)
            {
                if (VARIABLE.预加载)
                {
                    int i = index;
                    await 预加载字体(VARIABLE.下载地址, VARIABLE.Type, (f) =>
                    {
                        字体进度[i] = f;
                        float 总进度 = 0;
                        foreach (var VARIABLE in 字体进度)
                        {
                            总进度 += VARIABLE;
                        }

                        float 总 = 总进度 / 预加载数量;
                        总进度Call?.Invoke(总);
                    });
                    index += 1;
                }
            }
        }
    }
    
    public void Get微信字体(Action<Font> call)
    {
        if (微信字体 != null)
        {
            Debug.Log("使用了缓存微信字体");
            call?.Invoke(微信字体);
            return;
        }
        WX.GetWXFont(失败返回字体, (f) =>
        {
            call?.Invoke(f);
            // 字体缓存[自定义字体枚举.微信字体] = f;
            微信字体 = f;
        });
    }

    private Font 微信字体;

    // private Dictionary<自定义字体枚举, Font> 字体缓存 = new Dictionary<自定义字体枚举, Font>();
    private Dictionary<自定义字体枚举, byte[]> 字体缓存Byte = new Dictionary<自定义字体枚举, byte[]>();

    public async Task 预加载字体(string 地址,自定义字体枚举 名字,Action<float> 进度)
    {
        var 字体 = await 异步自定义下载字体(地址,名字.ToString(),进度);
        if (字体 == null)
        {
            Debug.LogError("没加载到字体");
        }
        else
        {
            Debug.Log("预加载完成：："+名字);
            if (!字体缓存Byte.ContainsKey(名字))
            {
                字体缓存Byte.Add(名字,字体);
            }
        }
    }

    public void Get自定义字体(自定义字体枚举 type,Action<byte[]> call)
    {
        if (字体缓存Byte.ContainsKey(type))
        {
            Debug.Log("使用了自定义字体"+type);
            call?.Invoke(字体缓存Byte[type]);
            return;
        }

        var config = 自定义字体配置s.FirstOrDefault(f => f.Type == type);
        if (config != null)
        {
            Debug.Log("需要下载字体"+type);
            自定义字体下载2(
                config.下载地址,
                type.ToString(),
                (x) =>
                {
                    call?.Invoke(x);
                    字体缓存Byte[type] = x;
                });
        }
       
    }
    
    // public void 设置字体膨胀(bool 加)
    // {
    //     float 值 = 字体膨胀 * 100;
    //     值 = 加 ? 值++ : 值--;
    //     字体膨胀 = 值 / 100f;
    //     文字材质球.SetFloat("_FaceDilate", 字体膨胀);
    //     膨胀文本.text = $"膨胀:{字体膨胀}";
    // }
    // public void 设置字体描边(bool 加)
    // {
    //     float 值 = 字体描边 * 100;
    //     值 = 加 ? 值++ : 值--;
    //     字体描边 = 值 / 100f;
    //     文字材质球.SetFloat("_OutlineWidth", 字体描边);
    //     描边文本.text = $"膨胀:{字体描边}";
    // }

    public async Task<byte[]> 异步自定义下载字体(string 地址,string name,Action<float> 进度变化)
    {
        UnityWebRequest www = UnityWebRequest.Get(地址);
        var 进度 = www.SendWebRequest();

        float cur = 0f;
        while (!进度.webRequest.isDone && string.IsNullOrEmpty(进度.webRequest.error))
        {
            cur = 进度.progress;
            进度变化?.Invoke(cur);
            await Task.Yield();
        }

        if (cur < 1f)
        {
            cur = 1f;
            进度变化?.Invoke(1);
        }
        
        
        // await www.SendWebRequest();
        
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Failed to load font: " + www.error);
            return null;
        }
        else
        {
            Debug.Log($"【下载完毕】");
            byte[] fontData = www.downloadHandler.data;

            // 保存字体文件到本地
            //   string fontFilePath = Application.persistentDataPath + "/downloadedFont.ttf";
            //   File.WriteAllBytes(fontFilePath, fontData);

            var inFontData = fontData;
            var ascent = 0;
            var descent = 0;
            var lineGap = 0;
            var unitsPerEm = 10;
            // 未经过充分测试，目前看fontSize不决定最终字体大小，此处只是为了换算lineHeight。如果游戏使用有问题，可以考虑让游戏侧传入字体大小
            var fSize = 16;


            return inFontData;
            // Font f = Font.CreateDynamicFontFromOSFont(inFontData, fSize);
            
            // var abBytes = Unity.FontABTool.UnityFontABTool.PacKFontAB(inFontData, name, 0, fSize, fSize * ascent, fSize * descent);
            // Font res = null;
            // try
            // {
            //     var ab = AssetBundle.LoadFromMemory(abBytes);
            //     if (ab != null)
            //     {
            //         Font[] fonts = ab.LoadAllAssets<Font>();
            //         if (fonts.Length != 0)
            //         {
            //             Debug.Log($"从 ab 加载字体。 abBytes:{abBytes.Length}");
            //             // 回调.Invoke(fonts[0]);
            //             res = fonts[0];
            //         }
            //         else
            //         {
            //             Debug.LogError($"LoadAllAssets failed, abBytes:{abBytes.Length}, fonts: {fonts.Length}");
            //         }
            //         ab.Unload(false);
            //     }
            //     else
            //     {
            //         Debug.LogError($"LoadFromMemory failed, Length: {abBytes.Length}");
            //     }
            // }
            // catch (Exception ex)
            // {
            //     Debug.LogError($"GetWXFont Exception, ex:{ex.ToString()}");
            // }
            //
            // return res;
        }
    }

    public  void 自定义字体下载2(string 地址,string name, System.Action<byte[]> 回调)
    {
        StartCoroutine(自定义字体下载3(地址,name, 回调));
    }

    private IEnumerator 自定义字体下载3(string 地址,string name, System.Action<byte[]> 回调)
    {
        UnityWebRequest www = UnityWebRequest.Get(地址);
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Failed to load font: " + www.error);
        }
        else
        {
            Debug.Log($"【下载完毕】");
            byte[] fontData = www.downloadHandler.data;

            // 保存字体文件到本地
         //   string fontFilePath = Application.persistentDataPath + "/downloadedFont.ttf";
         //   File.WriteAllBytes(fontFilePath, fontData);

            var inFontData = fontData;
            var ascent = 0;
            var descent = 0;
            var lineGap = 0;
            var unitsPerEm = 10;
            // 未经过充分测试，目前看fontSize不决定最终字体大小，此处只是为了换算lineHeight。如果游戏使用有问题，可以考虑让游戏侧传入字体大小
            var fSize = 16;

            回调.Invoke(inFontData);
            // Font f = Font.CreateDynamicFontFromOSFont(inFontData, fSize);
            
            // var abBytes = Unity.FontABTool.UnityFontABTool.PacKFontAB(inFontData, name, 0, fSize, fSize * ascent, fSize * descent);
            // try
            // {
            //     var ab = AssetBundle.LoadFromMemory(abBytes);
            //     if (ab != null)
            //     {
            //         Font[] fonts = ab.LoadAllAssets<Font>();
            //         if (fonts.Length != 0)
            //         {
            //             Debug.Log($"从 ab 加载字体。 abBytes:{abBytes.Length}");
            //             回调.Invoke(fonts[0]);
            //         }
            //         else
            //         {
            //             Debug.LogError($"LoadAllAssets failed, abBytes:{abBytes.Length}, fonts: {fonts.Length}");
            //             回调.Invoke(null);
            //         }
            //         ab.Unload(false);
            //     }
            //     else
            //     {
            //         Debug.LogError($"LoadFromMemory failed, Length: {abBytes.Length}");
            //         回调.Invoke(null);
            //     }
            // }
            // catch (Exception ex)
            // {
            //     Debug.LogError($"GetWXFont Exception, ex:{ex.ToString()}");
            //     回调.Invoke(null);
            // }
        }
    }



    bool 是否字体文件(string path)
    {
        string extension = Path.GetExtension(path).ToLower();
        // 判断文件扩展名是否为.ttf或.otf
        return extension == ".ttf" || extension == ".otf";
    }
    
#if UNITY_EDITOR

#endif
    #endregion

#region 广告功能
    [FoldoutGroup("广告设置"), EnumToggleButtons,ShowIf("@广告功能 == 开关.开")]  public 开关 免广告 = 开关.关;
    [FoldoutGroup("广告设置"), EnumToggleButtons,ShowIf("@广告功能 == 开关.开")]  public 开关 预加载广告 = 开关.开;
    [HideInInspector, FoldoutGroup("广告设置"), Tooltip("广告与分享混合概率出现。"), EnumToggleButtons, ShowIf("@广告功能 == 开关.开")] public 开关 混合模式 = 开关.开;
    [HideInInspector,FoldoutGroup("广告设置/混合设置"),Range(0,5), SuffixLabel("次", overlay: true), ShowIf("@混合模式 == 开关.开&&广告功能 == 开关.开")] public int 必定分享次数=1;
    [HideInInspector,FoldoutGroup("广告设置/混合设置"), Range(0, 100), SuffixLabel("%", overlay: true), ShowIf("@混合模式 == 开关.开&&广告功能 == 开关.开")] public int 广告比重=50;
    [HideInInspector,FoldoutGroup("广告设置/混合设置"), Tooltip("每次分享增加下次广告的比重。"), EnumToggleButtons, ShowIf("@混合模式 == 开关.开&&广告功能 == 开关.开")] public 开关 累加模式 = 开关.开;
    [HideInInspector,FoldoutGroup("广告设置/混合设置"), Range(1, 5), SuffixLabel("%", overlay: true), ShowIf("@混合模式 == 开关.开&&累加模式 == 开关.开&&广告功能 == 开关.开")] public int 累加比例=2;
    [InfoBox("设置上限最低应>广告比重,否则将不再累加。", InfoMessageType.Warning, "@累加上限<=广告比重&&广告功能 == 开关.开")]
    [HideInInspector,FoldoutGroup("广告设置/混合设置"), Range(1, 100), SuffixLabel("%", overlay: true), ShowIf("@混合模式 == 开关.开&&累加模式 == 开关.开&&广告功能 == 开关.开")] public int 累加上限=90;
    [BoxGroup("广告设置/ID设置"),GUIColor("@激励视频广告ID.Length>0?Color.white:Color.red"), ShowIf("@广告功能 == 开关.开")] public string 激励视频广告ID;
    [HideInInspector,FoldoutGroup("广告设置/ID设置"), GUIColor("@插屏广告ID.Length>0?Color.white:Color.red"), ShowIf("@广告功能 == 开关.开")] public string 插屏广告ID;
    [HideInInspector,FoldoutGroup("广告设置/ID设置/原生模板广告"),LabelText("刷新间隔"),MinValue(30), SuffixLabel("秒", overlay: true), Range(30, 120), ShowIf("@广告功能 == 开关.开")] public int 原生模板广告刷新间隔 = 30;
    [HideInInspector,FoldoutGroup("广告设置/ID设置/原生模板广告"), TableList(HideToolbar =true,AlwaysExpanded =true,IsReadOnly =true), ShowIf("@广告功能 == 开关.开")]
    public List<广告设置> 模板广告 = new List<广告设置> {
    new 广告设置{名称 = "上横广告" },
    new 广告设置{名称 = "下横广告" },
    new 广告设置{名称 = "左竖广告" },
    new 广告设置{名称 = "右竖广告" },
    new 广告设置{名称 = "中间广告" },
    new 广告设置{名称 = "左格广告" },
    new 广告设置{名称 = "右格广告" },
    };
    [HideInInspector,FoldoutGroup("广告设置/ID设置/Banner广告"), LabelText("刷新间隔"), MinValue(30), SuffixLabel("秒", overlay: true),Range(30,120), ShowIf("@广告功能 == 开关.开")] public int Banner广告刷新间隔 = 30;
    [HideInInspector,FoldoutGroup("广告设置/ID设置/Banner广告"), TableList(HideToolbar = true, AlwaysExpanded = true, IsReadOnly = true), ShowIf("@广告功能 == 开关.开")]
    public List<广告设置> Banner广告 = new List<广告设置> {
    new 广告设置{名称 = "上广告" },
    new 广告设置{名称 = "下广告" },
    };



    public void 免广告设置(bool 广告开关)
    {
        if (广告开关)
        {
            免广告 = 开关.开;
        }
        else
        {
            免广告 = 开关.关;
        }
    }

    // private List<WXRewardedVideoAd> 预加载广告 = new List<WXRewardedVideoAd>();

    private void 补充广告()
    {
        if (广告功能 == 开关.开 && 免广告 == 开关.关 && 预加载广告 == 开关.开)
        {
            Debug.Log("进行补充广告");
            缓存激励视频广告 = null;
            开始预加载激励视频();
        }
    }

    WXRewardedVideoAd 缓存激励视频广告;
    private void 开始预加载激励视频(){
        
        // GameButton.看广告全屏蔽 = true;
        
        WXCreateRewardedVideoAdParam 参数 = new WXCreateRewardedVideoAdParam();
        参数.adUnitId = 激励视频广告ID;
        参数.multiton = false; // or true, depending on your needs
        缓存激励视频广告 = WX.CreateRewardedVideoAd(参数);
        
        缓存激励视频广告.Load((成功) =>
        {
            Debug.Log(成功.errCode+成功.errMsg);
            发送消息("激励视频广告加载成功");
        }, (失败) =>
        {
            Debug.Log(失败.errCode+失败.errMsg);
            发送消息($"激励视频广告加载失败:{失败}", 2);
        });
    }

    /// <summary>
    /// 播放广告了？ , 广告目的, 广告参数1, 广告参数2
    /// </summary>
    public event Action<bool, string, string, string> 预留打点事件; 
    public void 播放广告(Action 成功方法, Action 失败方法=null,string 广告目的="",string 广告参数1="",string 广告参数2="")
    {
        if (免广告 == 开关.开)
        {
            预留打点事件?.Invoke(false,广告目的,广告参数1,广告参数2);
            return;
        }

        if (预加载广告 == 开关.开)
        {
            显示预加载激励视频广告(成功方法,失败方法);
        }
        else
        {
            显示激励视频广告(成功方法,失败方法);
        }
        预留打点事件?.Invoke(false,广告目的,广告参数1,广告参数2);
    }
    
    private bool 播放广告中;
    private void 显示预加载激励视频广告(Action 成功方法, Action 失败方法)
    {
        if(播放广告中) return;
        播放广告中 = true;
        
        if (免广告 == 开关.开)
        {
            播放广告中 = false;
            成功方法();
            return;
        }
        
        if (缓存激励视频广告 != null)
        {
            缓存激励视频广告.Show((广告显示成功) =>
            {
                发送消息("激励视频广告显示成功");
                广告失败次数=0;
                缓存激励视频广告.OnClose((结果) =>
                {
                    播放广告中 = false;
                    if (结果.isEnded)
                    {
                        成功方法();
                        if (累加模式 == 开关.开)
                        {
                            本次累计广告次数++;
                            if(广告比重< 累加上限)
                            {
                                广告比重 += 累加比例;
                            }
                        }
                        发送消息("正常播放结束，可以下发游戏奖励");
                    }
                    else
                    {
                        失败方法();
                        发送消息("播放中途退出，不下发游戏奖励");
                    }

                    缓存激励视频广告 = null;
                    补充广告();
                });
            }, (广告显示失败) =>
            {
                // 播放广告中 = true; = false;
                Debug.Log("广告显示失败"+广告显示失败.errCode+广告显示失败.errMsg);
                发送消息($"激励视频广告显示失败:{广告显示失败}", 2);
                //如果组件的某次自动拉取失败，那么之后调用的 show() 将会被 reject。此时可以调用 RewardedVideoAd.load() 手动重新拉取广告。
                显示激励视频广告(成功方法, 失败方法);
            });
        }
        else
        {
            Debug.Log("还是经过加载广告");
            显示激励视频广告(成功方法, 失败方法);
        }
    }

    private int 广告失败次数=0;
    private void 显示激励视频广告(Action 成功方法, Action 失败方法)
    {
        if (免广告 == 开关.开)
        {
            播放广告中 = false;
            成功方法();
            return;
        }
        
        WXCreateRewardedVideoAdParam 参数 = new WXCreateRewardedVideoAdParam();
        参数.adUnitId = 激励视频广告ID;
        参数.multiton = false; // or true, depending on your needs
        WXRewardedVideoAd 激励视频广告 = WX.CreateRewardedVideoAd(参数);
        激励视频广告.Load((成功) =>
        {
            发送消息("激励视频广告加载成功");
            激励视频广告.Show((广告显示成功) =>
            {
                发送消息("激励视频广告显示成功");
                广告失败次数=0;
                激励视频广告.OnClose((结果) =>
                {
                    播放广告中 = false;
                    if (结果.isEnded)
                    {
                        成功方法();
                        本次累计广告次数++;
                        if (广告比重 < 累加上限 && 累加模式 == 开关.开)
                        {
                            广告比重 += 累加比例;
                        }

                        发送消息("正常播放结束，可以下发游戏奖励");
                    }
                    else
                    {
                        失败方法();
                        发送消息("播放中途退出，不下发游戏奖励");
                    }

                    缓存激励视频广告 = null;
                    补充广告();
                });
            }, (广告显示失败) =>
            {
                // 播放广告中 = false;
                发送消息($"激励视频广告显示失败:{广告显示失败}", 2);
                //如果组件的某次自动拉取失败，那么之后调用的 show() 将会被 reject。此时可以调用 RewardedVideoAd.load() 手动重新拉取广告。
                广告失败次数++;
                if (广告失败次数 <= 5)
                {
                    显示激励视频广告(成功方法, 失败方法);
                }
                else
                {
                    播放广告中 = false;
                }
            });
        }, (失败) =>
        {
            发送消息($"激励视频广告加载失败:{失败}", 2);
        });
    }

    public void 显示插屏广告(Action 成功方法, Action 失败方法)
    {
        if (免广告 == 开关.开)
        {
            成功方法();
            return;
        }
        WXCreateInterstitialAdParam 参数 = new WXCreateInterstitialAdParam();
        参数.adUnitId = 插屏广告ID;
        WXInterstitialAd 插屏广告 = WX.CreateInterstitialAd(参数);

        插屏广告.Show((广告显示成功) =>
        {
            发送消息("插屏广告显示成功");
        }, (广告显示失败) =>
        {
            发送消息($"插屏广告显示失败:{广告显示失败}", 2);
            失败方法();
        });
    }

    public void 显示Banner广告(int 上下)
    {
        if (上下 != 0 || 上下 != 1)
        {
            发送消息($"Banner广告上下设置错误:{上下}", 2);
            return;
        }
        if (!Banner广告[上下].启) return;
        if (Banner广告[上下].Banner广告 == null)
        {
            Banner广告[上下].Banner广告 = 创建Banner广告(Banner广告[上下].ID);
        }
        else
        {
            Banner广告[上下].Banner广告.Show();
        }
        if (上下 == 1)
        {
            Banner广告[上下].Banner广告.style.top = (int)屏幕高度 - Banner广告[上下].Banner广告.style.realHeight;
        }

    }
    WXBannerAd 创建Banner广告(string 对应Banner广告ID)
    {
        WXCreateBannerAdParam 参数 = new WXCreateBannerAdParam();
        Style 样式 = new Style();
        样式.width = (int)屏幕宽度;
        参数.adUnitId = 对应Banner广告ID;
        参数.adIntervals = Banner广告刷新间隔;
        参数.style = 样式;
        WXBannerAd Banner广告 = WX.CreateBannerAd(参数);
        Banner广告.Show((广告显示成功) =>
        {
            发送消息("Banner广告显示成功");
        }, (广告显示失败) =>
        {
            发送消息($"Banner广告显示失败:{广告显示失败}", 2);
        });
        return Banner广告;
    }

    public void 显示所有模板广告()
    {
        for (int i = 0; i < 6; i++)
        {
            显示模板广告(i);
        }
    }
    public void 显示模板广告(int 位置编号)
    {
        if (位置编号 > 6)
        {
            发送消息($"模板广告位置设置错误:{位置编号}", 2);
            return;
        }
        if (!模板广告[位置编号].启) return;
        if (模板广告[位置编号].模板广告 == null)
        {
            WXCustomAd 广告 = 创建原生模板广告(模板广告[位置编号].ID);
            模板广告[位置编号].模板广告 = 广告;
        }
        else
        {
            switch (位置编号)
            {
                case 0: //上横
                    模板广告[位置编号].模板广告.style.top = 0;
                    模板广告[位置编号].模板广告.style.left = 0;
                    break;
                case 1: //下横
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 - 100;
                    模板广告[位置编号].模板广告.style.left = 0;
                    break;
                case 2: //左竖
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 / 2 + 100;
                    模板广告[位置编号].模板广告.style.left = 10;

                    break;
                case 3: //右竖
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 / 2 + 100;
                    模板广告[位置编号].模板广告.style.left = (int)屏幕宽度 - 10 - 50;
                    break;
                case 4: //中间
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 / 2 + 100;
                    模板广告[位置编号].模板广告.style.left = (int)屏幕宽度 / 2 + 100;
                    break;
                case 5: //左单格
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 / 2 + 150;
                    模板广告[位置编号].模板广告.style.left = 10;
                    break;
                case 6: //右单格
                    模板广告[位置编号].模板广告.style.top = (int)屏幕高度 / 2 + 150;
                    模板广告[位置编号].模板广告.style.left = (int)屏幕宽度 - 10 - 50;
                    break;
            }
            模板广告[位置编号].模板广告.Show();
        }
    }
    

    WXCustomAd 创建原生模板广告(string 对应模板广告ID)
    {
        WXCreateCustomAdParam 参数 = new WXCreateCustomAdParam();
        参数.adUnitId = 对应模板广告ID;
        参数.adIntervals = 原生模板广告刷新间隔;
        WXCustomAd 原生模板广告 = WX.CreateCustomAd(参数);
        原生模板广告.Show((广告显示成功) =>
        {
            发送消息("原生模板广告显示成功");
        }, (广告显示失败) =>
        {
            发送消息($"原生模板广告显示失败:{广告显示失败}", 2);
        });
        return 原生模板广告;
    }
    #endregion

#region 分享功能
    [InfoBox("默认使用当前小游戏的昵称。", InfoMessageType.Info, "@分享标题.Count == 0 && 分享功能 == 开关.开")]
    [FoldoutGroup("分享设置/随机分享配置"),ShowIf("@分享功能 == 开关.开")] public List<分享Config> 分享配置;
    // [FoldoutGroup("分享设置/截图分享配置"),ShowIf("@分享功能 == 开关.开")] public List<分享Config> 分享配置;
    

    [FoldoutGroup("分享设置"), Required("请输入分享标题。"), ShowIf("@分享功能 == 开关.开")] public List<string> 分享标题 = new List<string>();
    [FoldoutGroup("分享设置"), EnumToggleButtons, ShowIf("@分享功能 == 开关.开")] public 分享图片 图片类型 = 分享图片.Icon;
    [InfoBox("请输入MP管理后台的图片地址信息。", InfoMessageType.Warning, "@审核图片.Count == 0 && 分享功能 == 开关.开")]
    [FoldoutGroup("分享设置"), Required("请输入MP管理后台的图片地址信息。"),ShowIf("@图片类型 == 分享图片.审核图 && 分享功能 == 开关.开")] public List<审核图片> 审核图片 = new List<审核图片>();
    [FoldoutGroup("分享设置"), EnumToggleButtons, ShowIf("@分享功能 == 开关.开")] public 开关 分享时间判断 = 开关.关;
    [FoldoutGroup("分享设置"), SuffixLabel("秒", overlay: true),ShowIf("@分享时间判断 ==开关.开 && 分享功能 == 开关.开"), Range(1, 5)] public int 分享成功判定 = 2;
    [InfoBox("请输入失败提示。", InfoMessageType.Warning, "@分享失败提示.Count == 0 && 分享功能 == 开关.开")]
    [FoldoutGroup("分享设置"), Required("请输入失败提示。"), ShowIf("@分享时间判断 ==开关.开 && 分享功能 == 开关.开")] public List<string> 分享失败提示 = new List<string>();


    public void 截图分享(分享截图大小 rect)
    {
        var size = rect.Get分享截图大小();
        var 截图 = WXCanvas.ToTempFilePathSync(new WXToTempFilePathParam()
        {
            x = size.Item1,
            y = size.Item2,
            width = size.Item3,
            height = size.Item4,
            destWidth = 500,
            destHeight = 400,
        });
        
        ShareAppMessageOption 分享设置 = new ShareAppMessageOption();
        分享设置.imageUrl = 截图;
        分享设置.title = "Test截图";
        WX.ShareAppMessage(分享设置);
    }
    public void 分享(Action 成功方法, Action 失败方法)
    {
        本次累计分享次数++;
        ShareAppMessageOption 分享设置 = new ShareAppMessageOption();
        if (分享标题.Count > 0)
        {
            int 随机数 = UnityEngine.Random.Range(0, 分享标题.Count);
            分享设置.title = 分享标题[随机数];
        }
        switch (图片类型)
        {
            case 分享图片.Icon:
                //不指定转发图片，默认会显示一个小程序的 logo。
                break;
            case 分享图片.截图:
                int ShareHeight = UnityEngine.Screen.height / 3;
                var 截图 = WXCanvas.ToTempFilePathSync(new WXToTempFilePathParam()
                {
                    x = (Screen.width - ShareHeight) / 2,
                    y = ShareHeight,
                    width = ShareHeight,
                    height = ShareHeight,
                    destWidth = ShareHeight,
                    destHeight = ShareHeight,
                });
                分享设置.imageUrl = 截图;
                break;
            case 分享图片.审核图:
                int 随机数 = UnityEngine.Random.Range(0, 审核图片.Count);
                分享设置.imageUrlId = 审核图片[随机数].编号;
                分享设置.imageUrl = 审核图片[随机数].地址;
                break;
        }
        StartCoroutine(分享等待时间(成功方法, 失败方法));
        WX.ShareAppMessage(分享设置);

    }
    public void 分享信息到群聊()
    {
        // 分享信息到群聊
        WX.ShareAppMessage(new ShareAppMessageOption()
        {
            // 标题
            title = "最强战力排行榜！谁是第一？",
            // 分享的路径参数，与OnShow约定进行判断
            query = "action=show_group_rank",
            // 封面 - 后续可更换为自己的，但需要在微信公众平台配置
            // https://developers.weixin.qq.com/minigame/dev/guide/open-ability/share/share.html
            imageUrl = "https://mmgame.qpic.cn/image/5f9144af9f0e32d50fb878e5256d669fa1ae6fdec77550849bfee137be995d18/0",
        });
    }
    IEnumerator 分享等待时间(Action 成功方法, Action 失败方法)
    {
        分享等待 = 0;
        分享中 = true;
        //监听小游戏回到前台
        WX.OnShow((a) => {
            分享中 = false;
            if (分享等待 >= 分享成功判定 && 分享时间判断 == 开关.开)
            {
                成功方法();
            }
            else
            {
                失败方法();
            }
        });
        while (分享中)
        {
            yield return new WaitForSecondsRealtime(1);
            分享等待++;
        }
    }
#endregion

#region 游戏圈功能
    //【声明】--------------------------------
    private RectTransform 游戏圈按钮;
    private WXGameClubButton 创建的游戏圈按钮;
    [InfoBox("根据按钮名称获得按钮位置与大小，按钮样式无效。", InfoMessageType.Warning)]
    [FoldoutGroup("游戏圈设置"), ShowIf("@游戏圈功能 == 开关.开"), LabelText("按钮名称")] public string 游戏圈按钮名称;
    [FoldoutGroup("游戏圈设置"), ShowIf("@游戏圈功能 == 开关.开"), LabelText("指定链接")] public string 游戏圈按钮指定链接;

    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开"), EnumToggleButtons, LabelText("按钮类型")] public 按钮类型 游戏圈类型 = 按钮类型.图片按钮;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && !string.IsNullOrEmpty(游戏圈按钮指定链接)"), EnumToggleButtons, LabelText("红点")] public 开关 游戏圈按钮红点 = 开关.开;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && 游戏圈类型 == 按钮类型.图片按钮"), LabelText("背景图片")] public string 游戏圈按钮的背景图片;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && 游戏圈类型 == 按钮类型.文本按钮"), LabelText("文字显示")] public string 游戏圈按钮文字;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && 游戏圈类型 == 按钮类型.文本按钮"), LabelText("文字字号")] public int 游戏圈按钮文字字号;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && 游戏圈类型 == 按钮类型.文本按钮"), EnumToggleButtons, LabelText("对齐方式")] public 对齐方式 游戏圈按钮文字对齐方式 = 对齐方式.中;
    [FoldoutGroup("游戏圈设置/样式"), ShowIf("@游戏圈功能 == 开关.开 && 游戏圈类型 == 按钮类型.图片按钮"), EnumToggleButtons, LabelText("按钮图标")] public 游戏圈图标样式 游戏圈按钮图标 = 游戏圈图标样式.绿标;
    


    bool 获取游戏圈按钮()
    {
        if (string.IsNullOrEmpty(游戏圈按钮名称))
        {
            游戏圈按钮 = null;
            return false;
        }
        else
        {
            //Debug.Log($"切换场景或的按钮位置:{GameObject.Find(用户信息授权按钮名).GetComponent<RectTransform>()}");
            游戏圈按钮 = GameObject.Find(游戏圈按钮名称).GetComponent<RectTransform>();
            return true;
        }
    }
    

    void 设置游戏圈按钮大小( int x, int y, int 宽, int 高)
    {
        创建的游戏圈按钮.style.left = x;
        创建的游戏圈按钮.style.top = y;
        创建的游戏圈按钮.style.width = 宽;
        创建的游戏圈按钮.style.height = 高;
    }
    public void 创建游戏圈按钮()
    {
        WXCreateGameClubButtonParam 按钮属性 = new WXCreateGameClubButtonParam();
        switch (游戏圈类型)
        {
            case 按钮类型.文本按钮:
                按钮属性.type = GameClubButtonType.text;
                break;
            case 按钮类型.图片按钮:
                按钮属性.type = GameClubButtonType.image;
                break;
        }
        按钮属性.text = 游戏圈按钮文字;
        if (!string.IsNullOrEmpty(游戏圈按钮的背景图片))
        {
            按钮属性.openlink = 游戏圈按钮的背景图片;
        }
        //按钮属性.style 自动调整
        switch (游戏圈按钮文字对齐方式)
        {
            case 对齐方式.左:
                按钮属性.style.textAlign = GameClubButtonTextAlign.left;
                break;
            case 对齐方式.中:
                按钮属性.style.textAlign = GameClubButtonTextAlign.center;
                break;
            case 对齐方式.右:
                按钮属性.style.textAlign = GameClubButtonTextAlign.right;
                break;
        }
        按钮属性.style.fontSize = 游戏圈按钮文字字号;
        switch (游戏圈按钮图标)
        {
            case 游戏圈图标样式.黑标:
                按钮属性.icon = GameClubButtonIcon.dark;
                break;
            case 游戏圈图标样式.白标:
                按钮属性.icon = GameClubButtonIcon.white;
                break;
            case 游戏圈图标样式.绿标:
                按钮属性.icon = GameClubButtonIcon.green;
                break;
            case 游戏圈图标样式.白底绿标:
                按钮属性.icon = GameClubButtonIcon.light;
                break;
        }
        if (!string.IsNullOrEmpty(游戏圈按钮指定链接))
        {
            按钮属性.openlink = 游戏圈按钮指定链接;
        }
        按钮属性.hasRedDot = 游戏圈按钮红点 == 开关.开 ? true : false;
        创建的游戏圈按钮 = WX.CreateGameClubButton(按钮属性); 
        创建的游戏圈按钮.OnTap(() => { 游戏圈按钮.GetComponent<Button>().onClick.Invoke(); });
        发送消息($"创建游戏圈按钮完毕");
    }
    #endregion

#region 排行榜功能
    [InfoBox("1、需要先开启微信SDK功能【<color=red>使用好友关系链</color>】。" +
        "\n2、需要微信后台设置【<color=red>隐私协议</color>】与相应【<color=red>授权申请</color>】。" +
        "\n3、根据名称检索对应按钮，请确保检查场景内文件名的唯一性。" +
        "\n4、排行榜的样式需要修改或重写微信SDK对应文件才能实现。" +
        "\n5、在搜索、小游戏中心等微信场景下，可以展现同玩好友的排行榜", InfoMessageType.Warning, "@排行榜功能 ==开关.开")]
    [FoldoutGroup("排行榜设置"), LabelText("唯一标识"), ShowIf("@排行榜功能 ==开关.开")] public string 排行榜唯一标识;
    [FoldoutGroup("排行榜设置"), ShowIf("@排行榜功能 ==开关.开"), InlineButton("@检测名称(排行榜显示按钮名称)", Label = "检测", Icon = SdfIconType.Search), LabelText("显示按钮名称")] public string 排行榜显示按钮名称;
    [FoldoutGroup("排行榜设置"), ShowIf("@排行榜功能 ==开关.开"), InlineButton("@检测名称(排行榜关闭按钮名称)", Label = "检测", Icon = SdfIconType.Search), LabelText("关闭按钮名称")] public string 排行榜关闭按钮名称;
    [FoldoutGroup("排行榜设置"), ShowIf("@排行榜功能 ==开关.开"), InlineButton("@检测名称(排行榜显示区域名称)", Label = "检测", Icon = SdfIconType.Search), LabelText("显示区域名称")] public string 排行榜显示区域名称;
    private RectTransform  排行榜唤出按钮;
    private RectTransform 排行榜关闭按钮;
    private RawImage 排行榜显示区域;
#if UNITY_EDITOR
    [Button("图片",Icon = SdfIconType.CardImage), BoxGroup("排行榜设置/模板设置"), HorizontalGroup("排行榜设置/模板设置/1"), ShowIf("@排行榜功能 ==开关.开"), ShowInInspector] private void 排行榜图片()
    {
        打开路径目录("Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/image/avatar.png");
    }
    [Button("模板", Icon = SdfIconType.CollectionFill), BoxGroup("排行榜设置/模板设置"), HorizontalGroup("排行榜设置/模板设置/1"), ShowIf("@排行榜功能 ==开关.开"), ShowInInspector] private void 排行榜模板()
    {
        打开路径目录("Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/tpls/friendRank.js");
    }
    [Button("框架", Icon = SdfIconType.Columns), BoxGroup("排行榜设置/模板设置"), HorizontalGroup("排行榜设置/模板设置/1"), ShowIf("@排行榜功能 ==开关.开"), ShowInInspector]  private void 排行榜模板框架()
    {
        打开路径目录("Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/styles/friendRank.js");
    }
    [InlineButton("@修改排行榜单位名(排行版单位名称)", Label = "修改", Icon = SdfIconType.Search)] public string 排行版单位名称;

    [Button(), BoxGroup("排行榜设置/模板设置")] public void 排行榜框架增加注解()
    {
        string 文件路径 = "Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/styles/friendRank.js";
        string 文件内容 = 读取文件(文件路径);
        if (!string.IsNullOrEmpty(文件内容))
        {
            string 修改内容 = 文件内容;
            修改内容 = 增加注解(修改内容, "container", "容器");
            修改内容 = 增加注解(修改内容, "rankList", "排行榜");
            修改内容 = 增加注解(修改内容, "list", "列表");
            修改内容 = 增加注解(修改内容, "listItem", "项目清单");
            修改内容 = 增加注解(修改内容, "rankBg", "项目清单背景");
            修改内容 = 增加注解(修改内容, "rankAvatarBg", "头像背景");
            修改内容 = 增加注解(修改内容, "rankAvatar", "头像");
            修改内容 = 增加注解(修改内容, "rankNameView", "排名名称查看");
            修改内容 = 增加注解(修改内容, "rankNameBg", "排名名称背景");
            修改内容 = 增加注解(修改内容, "rankName", "排名名称");
            修改内容 = 增加注解(修改内容, "rankScoreTip", "排名分数提示");
            修改内容 = 增加注解(修改内容, "rankScoreVal", "排名分数值");
            修改内容 = 增加注解(修改内容, "shareNameView", "分享名称查看");
            修改内容 = 增加注解(修改内容, "shareNameBg", "共享名称背景");
            修改内容 = 增加注解(修改内容, "shareName", "共享名");
            修改内容 = 增加注解(修改内容, "shareToBtn", "分享到按钮");
            修改内容 = 增加注解(修改内容, "shareBtnBg", "分享按钮背景");
            修改内容 = 增加注解(修改内容, "shareText", "分享文本");

            修改内容 = 增加注解(修改内容, "borderRadius", "边界半径");
            修改内容 = 增加注解(修改内容, "paddingLeft", "左内边距");
            修改内容 = 增加注解(修改内容, "paddingRight", "右内边距");
            修改内容 = 增加注解(修改内容, "flexDirection", "弹性方向");
            修改内容 = 增加注解(修改内容, "alignItems", "对齐项目");
            修改内容 = 增加注解(修改内容, "marginTop", "顶部边距");
            修改内容 = 增加注解(修改内容, "borderRadius", "边界半径");
            修改内容 = 增加注解(修改内容, "marginLeft", "左边距");
            修改内容 = 增加注解(修改内容, "fontSize", "字体大小");
            修改内容 = 增加注解(修改内容, "textOverflow", "文本溢出");
            修改内容 = 增加注解(修改内容, "lineHeight", "行高");

            保存排行榜单位文件(文件路径, 修改内容);
        }
        else
        {
            Debug.LogError("未找到关卡设置文件，文件已经已移位或存在。请确保文件位于: Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/tpls/friendRank.js");
        }
    }
    [Button(), BoxGroup("排行榜设置/模板设置")]
    public void 排行榜框架删除注解()
    {
        string 文件路径 = "Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/styles/friendRank.js";
        string 文件内容 = 读取文件(文件路径);
        if (!string.IsNullOrEmpty(文件内容))
        {
            string 修改内容 = 删除注解(文件内容);
            保存排行榜单位文件(文件路径, 修改内容);
        }
        else
        {
            Debug.LogError("未找到关卡设置文件，文件已经已移位或存在。请确保文件位于: Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/tpls/friendRank.js");
        }
    }
    void 修改排行榜单位名(string 单位名)
    {
        string 文件路径 = "Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/tpls/friendRank.js";
        string 文件内容 = 读取文件(文件路径);
        if (!string.IsNullOrEmpty(文件内容))
        {
            string 修改内容 = 修改文件中的文本(文件内容, 单位名);
            Debug.Log("修改文件内容: " + 修改内容);
            保存排行榜单位文件(文件路径, 修改内容);
        }
        else
        {
            Debug.LogError("未找到关卡设置文件，文件已经已移位或存在。请确保文件位于: Assets/WX-WASM-SDK-V2/Runtime/wechat-default/open-data/render/tpls/friendRank.js");
        }
    }
    string 读取文件(string 路径)
    {
        string 内容 = "";
        try
        {
            using (StreamReader 阅读器 = new StreamReader(路径)) // 读取文件内容
            {
                内容 = 阅读器.ReadToEnd();
            }
        }
        catch (Exception 错误)
        {
            Debug.LogError("读取文件时出错: " + 错误.Message);
        }
        return 内容;
    }

    string 修改文件中的文本(string 内容,string 单位名)
    {
       
        string 规格 = @"<text class=""rankScoreTip"" value=""(.+?)""></text>";               // 使用正则表达式找到目标内容
        string 替换 = $"<text class=\"rankScoreTip\" value=\"{单位名}\"></text>";        // 进行修改
        return Regex.Replace(内容, 规格, 替换);
    }
    string 增加注解(string 内容, string 目标内容, string 注解内容)
    {
        string[] lines = 内容.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); // 将内容按行分割

        bool 已添加注解 = false;

        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i].Contains($"{目标内容}:"))
            {
                // 找到包含目标内容的行
                if (!lines[i].Contains("//" + 注解内容))
                {
                    lines[i] += " //" + 注解内容; // 在该行末尾添加以//开头的注解内容
                    已添加注解 = true;
                   // break;
                }
            }
        }

        if (!已添加注解)
        {
            // 如果没有找到目标内容或者已经添加了相同注解，则不做任何操作
            return 内容;
        }

        return string.Join(Environment.NewLine, lines); // 将处理过的内容合并为字符串并返回
    }
    string 删除注解(string 内容)
    {
        string[] lines = 内容.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); // 将内容按行分割

        for (int i = 0; i < lines.Length; i++)
        {
            if (!lines[i].Contains("//"))
            {
                continue; // 如果不包含注解符号 "//"，则跳过当前行
            }

            int commentIndex = lines[i].IndexOf("//");
            lines[i] = lines[i].Substring(0, commentIndex); // 删除注解部分
        }

        return string.Join(Environment.NewLine, lines); // 将处理过的内容合并为字符串并返回
    }





    void 保存排行榜单位文件(string 文件路径, string 内容)
    {
        try     // 写入修改后的内容到文件中
        {
            using (StreamWriter sw = new StreamWriter(文件路径))
            {
                sw.Write(内容);
            }
            Debug.Log("文件保存成功。");
        }
        catch (Exception e)
        {
            Debug.LogError("保存文件时出错：" + e.Message);
        }
    }
    void 打开路径目录(string 路径)
    {
        Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(路径);
    }
#endif

  
    // void 群排行榜分享()
    // {
    //     /**
    //      * 使用群排行功能需要特殊设置分享功能，详情可见链接
    //      * https://developers.weixin.qq.com/minigame/dev/guide/open-ability/share/share.html
    //      */
    //     WX.UpdateShareMenu(new UpdateShareMenuOption()
    //     {
    //         withShareTicket = true,
    //         isPrivateMessage = true,
    //     });
    //
    //     /**
    //      * 群排行榜功能需要配合 WX.OnShow 来使用，整体流程为：
    //      * 1. WX.UpdateShareMenu 分享功能；
    //      * 2. 监听 WX.OnShow 回调，如果存在 shareTicket 且 query 里面带有启动特定 query 参数则为需要展示群排行的场景
    //      * 3. 调用 WX.ShowOpenData 和 WX.GetOpenDataContext().PostMessage 告知开放数据域侧需要展示群排行信息
    //      * 4. 开放数据域调用 wx.getGroupCloudStorage 接口拉取获取群同玩成员的游戏数据
    //      * 5. 将群同玩成员数据绘制到 sharedCanvas
    //      */
    //     //群排行榜功能需要配合 WX.OnShow 来使用. 监听 WX.OnShow 回调
    //     WX.OnShow((OnShowListenerResult res) =>
    //     {
    //         string shareTicket = res.shareTicket;
    //         Dictionary<string, string> query = res.query;
    //         //如果存在 shareTicket 且 query 里面带有启动特定 query 参数则为需要展示群排行的场景
    //         if (!string.IsNullOrEmpty(shareTicket) && query != null && query["action"] == "show_group_rank")
    //         {
    //             开放数据域通信 msgData = 开放数据域通信.展示群组排行榜(shareTicket);
    //
    //             string msg = JsonUtility.ToJson(msgData);
    //             // 展示排行榜
    //             渲染排行榜();
    //             // 通知开放数据域
    //             WX.GetOpenDataContext().PostMessage(msg);
    //         }
    //     });
    // }
    private void 渲染排行榜()
    {
        
        // 显示排行榜相关的Unity-UI
        // 排行榜UI.SetActive(true);
        //  RankBox.SetActive(true);
        // 注意这里传x,y,width,height是为了点击区域能正确点击，x,y 是距离屏幕左上角的距离，宽度传 (int)RankBody.rectTransform.rect.width是在canvas的UI Scale Mode为 Constant Pixel Size的情况下设置的。
        /**
         * 如果父元素占满整个窗口的话，pivot 设置为（0，0），rotation设置为180，则左上角就是离屏幕的距离
         * 注意这里传x,y,width,height是为了点击区域能正确点击，因为开放数据域并不是使用 Unity 进行渲染而是可以选择任意第三方渲染引擎
         * 所以开放数据域名要正确处理好事件处理，就需要明确告诉开放数据域，排行榜所在的纹理绘制在屏幕中的物理坐标系
         * 比如 iPhone Xs Max 的物理尺寸是 414 * ，如果排行榜被绘制在屏幕中央且物理尺寸为 200 * 200，那么这里的 x,y,width,height应当是 107,348,200,200896
         * x,y 是距离屏幕左上角的距离，宽度传 (int)RankBody.rectTransform.rect.width是在canvas的UI Scale Mode为 Constant Pixel Size的情况下设置的
         * 如果是Scale With Screen Size，且设置为以宽度作为缩放，则要这要做一下换算，比如canavs宽度为960，rawImage设置为200 则需要根据参考分辨率做一些换算
         * 不过不管是什么屏幕适配模式，这里的目的就是为了算出 RawImage 在屏幕中绝对的位置和尺寸
         */

        // CanvasScaler scaler = gameObject.GetComponent<CanvasScaler>();
        // var 参考分辨率 = scaler.参考分辨率;
        // 获取canvas的单位像素，即上面RankCanvas设置的大小
        RectTransform 区域 = 排行榜显示区域.rectTransform;
        var 参考分辨率 = new Vector2(1080, 1920);
        var p = 排行榜显示区域.transform.position;
        // 由于实际渲染是上下颠倒的，所以旋转属性的x需设置为180，
        if (排行榜显示区域.gameObject.transform.rotation.x != 180)
        {
            Quaternion 角度 = 排行榜显示区域.gameObject.transform.rotation;
            角度.x = 180;
            排行榜显示区域.gameObject.transform.rotation = 角度;
        }
        // 计算渲染的区域、大小，通知开放数据域初始化渲染
        // 这里的计算效果不一定理想，需根据实际慢慢调试
        // 此处设置的值可能影响排行榜单的滚动、点击等操作
        WX.ShowOpenData(排行榜显示区域.texture, (int)p.x, Screen.height - (int)p.y, (int)((Screen.width / 参考分辨率.x) * 区域.rect.width), (int)((Screen.width / 参考分辨率.x) * 区域.rect.height));
    }
   

    #endregion

#region 数据状态
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/分享", 0.3f), ReadOnly] public int 本次累计分享次数;
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/分享", 0.3f), ReadOnly] public int 本次累计广告次数;
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/分享", 0.2f), SuffixLabel("秒", overlay: true), ReadOnly] public int 分享等待;
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/分享"), LabelWidth(50), ReadOnly] public bool 分享中;
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/1"), ReadOnly] public string 当前场景;
    [FoldoutGroup("数据状态"), HorizontalGroup("数据状态/1"),EnumToggleButtons, ReadOnly] public 录屏状态 录屏状态;
    [FoldoutGroup("数据状态"), LabelWidth(50), ReadOnly] public bool SDK初始化;
    [FoldoutGroup("数据状态"), LabelWidth(50), ReadOnly] bool 加载中;

    void 设置加载中状态(bool 状态)
    {
        if (状态 && !加载中)
        {
            WX.ShowLoading(new ShowLoadingOption()
            {
                title = "加载中",
                mask = true,
                success = (加载显示成功) => { 加载中 = true; },
            });
        }
        if (!状态 && 加载中)
        {
            加载中 = false;
            WX.HideLoading(new HideLoadingOption()
            {
                noConflict = true,
            });
        }
    }
    #endregion

#region 系统信息
    //【声明】-------------------------------------------
    [FoldoutGroup("系统信息")]                                                                                                                                                                            public WeChatWASM.SystemInfo 系统信息;
    [FoldoutGroup("系统信息"),                                                                  EnumToggleButtons,                                                             LabelWidth(80),  ReadOnly] public 开关 调试;
    [FoldoutGroup("系统信息"),                                                                  EnumToggleButtons,                                                             LabelWidth(80),  ReadOnly] public 客户端平台 客户端平台;
    [FoldoutGroup("系统信息"),               HorizontalGroup("系统信息/1"),                                                                                                    LabelWidth(80),  ReadOnly] public string 操作系统版本;
    [FoldoutGroup("系统信息"),               HorizontalGroup("系统信息/1"),                                                                                                    LabelWidth(100), ReadOnly] public string 客户端基础库版本;
    [FoldoutGroup("系统信息"),               HorizontalGroup("系统信息/1"),                                                                                                    LabelWidth(100), ReadOnly] public string 宿主Appid;
    [BoxGroup("系统信息/设备"),              HorizontalGroup("系统信息/设备/1",0.2f),                             LabelText("品牌"),                                           LabelWidth(30),  ReadOnly] public string 设备品牌;
    [BoxGroup("系统信息/设备"),              HorizontalGroup("系统信息/设备/1",0.2f),                             LabelText("型号"),                                           LabelWidth(30),  ReadOnly] public string 设备型号;
    [BoxGroup("系统信息/设备"),              HorizontalGroup("系统信息/设备/1",0.1f),                             LabelText("性能"),                                           LabelWidth(30),  ReadOnly] public double 设备性能等级; //仅Android -2、0(无法运行)、-1(未知)、>=1(设备性能值,该值越高,设备性能越好)
    [BoxGroup("系统信息/设备"),              HorizontalGroup("系统信息/设备/1"),                EnumToggleButtons,LabelText("主题"),                                           LabelWidth(30),  ReadOnly] public 系统主题 系统主题;
    [BoxGroup("系统信息/微信信息"),          HorizontalGroup("系统信息/微信信息/1"),                                                                                                            ReadOnly] public string 微信语言;
    [BoxGroup("系统信息/微信信息"),          HorizontalGroup("系统信息/微信信息/1"),                                                                                                            ReadOnly] public string 微信版本号;
    [BoxGroup("系统信息/微信信息"),          HorizontalGroup("系统信息/微信信息/1"),                                                                                                            ReadOnly] public double 微信字体大小;
    [FoldoutGroup("系统信息/屏幕信息"),      HorizontalGroup("系统信息/屏幕信息/1"),                                                         SuffixLabel("px", overlay: true),                  ReadOnly] public double 状态栏高度;
    [FoldoutGroup("系统信息/屏幕信息"),      HorizontalGroup("系统信息/屏幕信息/1"),                                                                                                            ReadOnly] public double 窗口上边缘Y值;
    [FoldoutGroup("系统信息/屏幕信息"),      HorizontalGroup("系统信息/屏幕信息/2"),                                                                                                            ReadOnly] public double 设备像素比;
    [FoldoutGroup("系统信息/屏幕信息"),      HorizontalGroup("系统信息/屏幕信息/2"),            EnumToggleButtons,                                                                              ReadOnly] public 屏幕朝向 屏幕朝向;
    [BoxGroup("系统信息/屏幕信息/屏幕尺寸"), HorizontalGroup("系统信息/屏幕信息/屏幕尺寸/1"),                      LabelText("宽度"),        SuffixLabel("px", overlay: true),                  ReadOnly] public double 屏幕宽度;
    [BoxGroup("系统信息/屏幕信息/屏幕尺寸"), HorizontalGroup("系统信息/屏幕信息/屏幕尺寸/1"),                      LabelText("高度"),        SuffixLabel("px", overlay: true),                  ReadOnly] public double 屏幕高度;
    [BoxGroup("系统信息/屏幕信息/可用窗口"), HorizontalGroup("系统信息/屏幕信息/可用窗口/1"),                      LabelText("宽度"),        SuffixLabel("px", overlay: true),                  ReadOnly] public double 可用窗口宽度;
    [BoxGroup("系统信息/屏幕信息/可用窗口"), HorizontalGroup("系统信息/屏幕信息/可用窗口/1"),                      LabelText("高度"),        SuffixLabel("px", overlay: true),                  ReadOnly] public double 可用窗口高度;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/1"),            EnumToggleButtons, LabelText("相册"),                                                           ReadOnly] public 开关 相册权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/1"),            EnumToggleButtons, LabelText("摄像头"),                                                         ReadOnly] public 开关 摄像头权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/2"),            EnumToggleButtons, LabelText("麦克风"),                                                         ReadOnly] public 开关 麦克风权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/2"),            EnumToggleButtons, LabelText("蓝牙"),                                                           ReadOnly] public 开关 蓝牙权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/3"),            EnumToggleButtons, LabelText("Wi-Fi"),                                                          ReadOnly] public 开关 WiFi权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/3"),            EnumToggleButtons, LabelText("日历"),                                                           ReadOnly] public 开关 日历权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/4"),            EnumToggleButtons, LabelText("定位"),                                                           ReadOnly] public 开关 定位权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/4"),            EnumToggleButtons, LabelText("地理位置"),                                                       ReadOnly] public 开关 地理位置权限;
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/4"),            EnumToggleButtons, LabelText("模糊定位"),                                                       ReadOnly] public 开关 模糊定位;   //ios
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/5"),            EnumToggleButtons, LabelText("通知"),                                                           ReadOnly] public 开关 通知权限;   //ios
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/5"),            EnumToggleButtons, LabelText("通知带标记"),                                                     ReadOnly] public 开关 通知带标记权限; //ios
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/5"),            EnumToggleButtons, LabelText("通知带声音"),                                                     ReadOnly] public 开关 通知带声音权限; //ios
    [FoldoutGroup("系统信息/微信权限"),      HorizontalGroup("系统信息/微信权限/5"),            EnumToggleButtons, LabelText("通知带提醒"),                                                     ReadOnly] public 开关 通知带提醒权限; //ios



    public SystemInfo Get系统信息
    {
        get
        {
            if (系统信息 == null)
            {
                系统信息 = WX.GetSystemInfoSync();
                同步系统信息面板();
            }

            return 系统信息;
        }
    }

    void 同步系统信息面板()
    {
        if(系统信息==null) return;
        
        设备品牌            = 系统信息.brand;
        设备型号            = 系统信息.model;
        设备像素比          = 系统信息.pixelRatio;
        屏幕宽度            = 系统信息.screenWidth;
        屏幕高度            = 系统信息.screenHeight;
        可用窗口宽度        = 系统信息.windowWidth;
        可用窗口高度        = 系统信息.windowHeight;
        状态栏高度          = 系统信息.statusBarHeight;
        微信语言            = 系统信息.language;
        微信版本号          = 系统信息.version;
        操作系统版本        = 系统信息.system;
        微信字体大小        = 系统信息.fontSizeSetting;
        客户端基础库版本    = 系统信息.SDKVersion;
        设备性能等级        = 系统信息.benchmarkLevel;
        宿主Appid           = 系统信息.host.appId;
        相册权限            = 系统信息.albumAuthorized ? 开关.开 : 开关.关;
        摄像头权限          = 系统信息.cameraAuthorized? 开关.开: 开关.关;
        定位权限            = 系统信息.locationAuthorized ? 开关.开 : 开关.关;
        麦克风权限          = 系统信息.microphoneAuthorized ? 开关.开 : 开关.关;
        通知权限            = 系统信息.notificationAuthorized ? 开关.开 : 开关.关;
        通知带标记权限      = 系统信息.notificationBadgeAuthorized ? 开关.开 : 开关.关;
        通知带声音权限      = 系统信息.notificationSoundAuthorized ? 开关.开 : 开关.关;
        通知带提醒权限      = 系统信息.notificationAlertAuthorized ? 开关.开 : 开关.关;
        日历权限            = 系统信息.phoneCalendarAuthorized ? 开关.开 : 开关.关;
        蓝牙权限            = 系统信息.bluetoothEnabled ? 开关.开 : 开关.关;
        WiFi权限            = 系统信息.wifiEnabled ? 开关.开 : 开关.关;
        地理位置权限        = 系统信息.locationEnabled ? 开关.开 : 开关.关;
        模糊定位            = 系统信息.locationReducedAccuracy ? 开关.开 : 开关.关;
        调试                = 系统信息.enableDebug ? 开关.开 : 开关.关;
        switch (系统信息.platform)
        {
            case "ios":
                客户端平台 = 客户端平台.IOS;
                break;
            case "android":
                客户端平台 = 客户端平台.Android;
                break;
            case "windows":
                客户端平台 = 客户端平台.Windows;
                break;
            case "mac":
                客户端平台 = 客户端平台.Mac;
                break;
            case "devtools":
                客户端平台 = 客户端平台.Devtools;
                break;
        }
        switch (系统信息.theme)
        {
            case "light":
                系统主题 = 系统主题.浅色;
                break;
            case "dark":
                系统主题 = 系统主题.深色;
                break;
        }
        switch (系统信息.deviceOrientation)
        {
            case "portrait":
                屏幕朝向 = 屏幕朝向.竖屏;
                break;
            case "landscape":
                屏幕朝向 = 屏幕朝向.横屏;
                break;
        } //设备方向（注意：IOS客户端横屏游戏获取deviceOrientation可能不准，建议以屏幕宽高为准）
        发送消息($"获取系统信息,屏幕宽度{屏幕宽度} 屏幕高度:{屏幕高度} 设备像素比:{设备像素比} 可用窗口宽度:{可用窗口宽度} 可用窗口高度:{可用窗口高度} 状态栏高度:{状态栏高度}");
    }

    #endregion

#region 录屏
    public void 开启录屏()
    {
        var 录屏 = WX.GetGameRecorder();
        录屏.Start(new GameRecorderStartOption());
        录屏.On(
            "start", (开始) =>
            {
                发送消息("开始录屏。");
                录屏状态 = 录屏状态.录制中;
            });
        录屏.On(
            "stop", (结束) =>
            {
                发送消息("录屏结束。");
                录屏状态 = 录屏状态.未开启;
            });
        录屏.On(
            "pause", (暂停) =>
            {
                发送消息("录屏暂停。");
                录屏状态 = 录屏状态.暂停;
            });
        录屏.On(
            "resume", (恢复) =>
            {
                发送消息("恢复录屏。");
                录屏状态 = 录屏状态.录制中;
            });
        录屏.On(
            "abort", (舍弃) =>
            {
                发送消息("舍弃录屏。");
                录屏状态 = 录屏状态.未开启;
            });
        录屏.On(
            "timeUpdate", (更新事件) =>
            {
                //录制时间更新事件。在录制过程中触发该事件。
            });
        录屏.On(
            "error", (错误) =>
            {
                发送消息($"录屏错误:{错误}", 2);
                录屏状态 = 录屏状态.未开启;
            });
    }

    public void 暂停录屏()
    {
        WX.GetGameRecorder().Pause();
    }
    public void 结束录屏()
    {
        WX.GetGameRecorder().Stop();
    }
    public void 舍弃录屏()
    {
        WX.GetGameRecorder().Abort();
    }

    public void 录屏分享()
    {
        var 参数 = new OperateGameRecorderVideoOption();
        WX.OperateGameRecorderVideo(参数);
    }
#endregion

[Serializable]
public class GetOpenId
{
    public string session_key;
    public string openid;
    public bool Result;
    public string errcode;
    public string errmsg;
}
public void 只是登入()
{
    WX.Login(new LoginOption
    {
        timeout = 1000, // 超时时间，单位ms
        complete = (result) => 
        {
            发送消息("完成登录Login操作。");
        },
        fail = (error) => {
            发送消息(error.errMsg);
            微信提示消息("登录失败请重试", "error", true, 3000);
        },
        success = (result) => {
            发送消息("完成登录成功。");
        },
    });

}

public void Add初始化其他事件(UnityAction ac)
{
    if (SDK初始化)
    {
        ac?.Invoke();
    }
    else
    {
        // 微信初始化其他事件.RemoveListener(ac);
        // 微信初始化其他事件.RemoveListener(ac);
    }
}
}
#region 字体配置窗口
#if UNITY_EDITOR
    #region 字体文件
[Serializable]
public class 字体文件
{
    [TableColumnWidth(30, resizable: false),ReadOnly] public int 编号;
    [TableColumnWidth(120, resizable: false), ReadOnly] public string 名称;
    [TableColumnWidth(150, resizable: false), ReadOnly] public string 文件类型;
    [ReadOnly] public string 文件路径;
    [Button(Icon = SdfIconType.GeoAltFill), TableColumnWidth(80, resizable: false), ShowInInspector] void 定位文件()
    {
        EditorGUIUtility.PingObject(AssetDatabase.LoadMainAssetAtPath(文件路径)); // 提示  
    }
    [ReadOnly] public string 相对路径;
    [TableColumnWidth(30, resizable: false),ReadOnly,GUIColor("@配置?Color.green:Color.red")] public bool 配置;
    [Button("打开/修改文件", Style = ButtonStyle.FoldoutButton,Icon = SdfIconType.Wrench), TableColumnWidth(150, resizable: false), ShowInInspector] public void 修改文件配置([LabelWidth(100)] bool 修改,[LabelWidth(100)] bool 配置内容)
    {
        if (文件类型.Contains("预制体"))
        {
            Debug.Log("预制体 ");
            GameObject 场景 = AssetDatabase.LoadAssetAtPath<GameObject>(文件路径);
            if (场景 != null)
            {
                if (!修改)
                {
                    AssetDatabase.OpenAsset(场景); // 在场景窗口中打开对象  
                    Debug.Log("打开 ");
                }
                Transform 根对象 = 场景.transform;
                按路径查找对象(EditorSceneManager.GetActiveScene(), 根对象, 1, 修改, 配置内容, "预制体"); //预制体
            }
            else
            {
                Debug.LogWarning("找不到场景: " + 文件路径);
            }
        }
        if (文件类型.Contains("场景"))
        {
            string 当前场景 = EditorSceneManager.GetActiveScene().path;
            if (文件路径 != 当前场景)                           //目标场景不是当前场景的情况下
            {
                if (EditorSceneManager.GetActiveScene().isDirty) //场景有修改
                {
                    int 选择 = EditorUtility.DisplayDialogComplex("保存场景", "当前场景已经被修改，是否修改场景并打开新场景？", "是", "否", "取消");
                    switch (选择)
                    {
                        case 0:
                            EditorSceneManager.SaveOpenScenes();
                            打开场景(修改, 配置内容, "目标场景不是当前场景的情况下,保存当前修改场景,再打开新的目标场景");
                            break;
                        case 1:
                            打开场景(修改, 配置内容, "目标场景不是当前场景的情况下,不保存，直接打开目标场景");
                            break;
                        case 2:
                            // 用户选择取消保存，放弃打开目标场景的操作
                            break;
                    }
                }
                else
                {
                    打开场景(修改, 配置内容, "目标场景不是当前场景的情况下，且当前场景没有修改，可以后台打开目标场景");//
                }
            }
            else
            {
                场景内找到根对象(EditorSceneManager.GetActiveScene(), 修改, 配置内容, "目标场景与当前场景相同，不需要再次打开，直接执行查找对象的操作");
            }
        }
    }//1


    void 打开场景(bool 修改, bool 配置内容,string 打开说明,bool 单个=false)
    {
        OpenSceneMode 打开模式 = OpenSceneMode.Single;
        if (修改 || 单个)
        {
            打开模式 = OpenSceneMode.Additive; //修改模式下，以添加的形式打开场景
        }
        Debug.Log($"【打开场景】 - 模式:{打开模式}");
        Scene 场景 = EditorSceneManager.OpenScene(文件路径, 打开模式);    // 打开场景
        if (场景.isLoaded)                                                                   // 如果场景已加载
        {
            场景内找到根对象(场景,修改, 配置内容, 打开说明);
            if (修改)
            {
                Debug.Log("【关闭场景】");
                EditorSceneManager.CloseScene(场景, true);         // 效果关闭场景
            }
        }
    }//2
    void 场景内找到根对象(Scene 场景,bool 修改, bool 配置内容,string 说明)
    {
        GameObject[] 根物体 = 场景.GetRootGameObjects();
        foreach (GameObject 物体 in 根物体)
        {
            按路径查找对象(场景,物体.transform, 1, 修改, 配置内容, 说明);//场景，需要修改
        }
    }//3
    void 按路径查找对象(Scene 场景, Transform 父对象, int 指数 ,bool 修改,bool 配置内容,string 说明)
    {
        Transform 目标对象 = null;
        string[] 路径部分 = 相对路径.Split('/');
        if (路径部分.Length == 1) // 只有自身，不需要查找子对象
        {
            目标对象 = 父对象;
        }
        foreach (Transform 子对象 in 父对象)
        {
            if (子对象.name == 路径部分[指数])
            {
                if (指数 == 路径部分.Length - 1)
                {
                    目标对象 = 子对象; //选中
                    break;
                }
                else
                {
                    按路径查找对象(场景,子对象, 指数 + 1, 修改, 配置内容, 说明); //自循环
                }
            }
        }
        if (目标对象 != null)
        {
            修改文字配置(目标对象.gameObject,场景,修改,配置内容,说明);
        }
        else
        {
            if (路径部分.Length == 指数) 
            {
                Debug.LogWarning("找不到文件路径指定的物体: " + 文件路径);
            }
        }
    }//4
    void 修改文字配置(GameObject 目标对象, Scene 场景, bool 修改 ,bool 配置内容,string 说明)
    {
        Debug.Log($"【修改文字配置】 目标对象：{目标对象} -场景： {场景} - 修改：{修改} - 配置内容：{配置内容} - 说明：{说明}");
        刷新配置信息(目标对象);
        if (修改)
        {
            if (配置内容)
            {
                if (!配置)
                {
                    目标对象.AddComponent<FontSetting>();
                    保存场景修改(目标对象, 场景, $"{说明} - 增加配置");
                }
            }
            else
            {
                if (配置)
                {
                    UnityEditor.Undo.DestroyObjectImmediate(目标对象.GetComponent<FontSetting>());
                    保存场景修改(目标对象, 场景, $"{说明} - 清除配置");
                }
            }
        }
        else
        {
            Selection.activeGameObject = 目标对象; //选中
            EditorGUIUtility.PingObject(Selection.activeGameObject); // 提示  
        }
    }//5
    void 保存场景修改(GameObject 目标对象, Scene 场景,string 消息)
    {
        Debug.Log($"【保存场景】 目标对象：{目标对象} - {消息}");
        刷新配置信息(目标对象);
        EditorSceneManager.SaveScene(场景);
    }
    void 刷新配置信息(GameObject 目标对象)
    {
        配置 = 目标对象.GetComponent<FontSetting>() ? true : false;
    }
}
#endregion
    #region 窗口
[EditorWindowTitle(title = "字体配置窗口")]
public class FontSettingsWindows : OdinEditorWindow
{
    public static FontSettingsWindows 字体配置窗口;
    [MenuItem("微信小游戏 / 字体配置")]
    public static void Open()
    {
        字体配置窗口 = (FontSettingsWindows)GetWindow(typeof(FontSettingsWindows));
        GUIContent titleContent = new GUIContent();
        titleContent.text = "字体配置窗口";
        字体配置窗口.titleContent = titleContent;
        字体配置窗口.Show();

    }
    string 提示;
    int 数量;
    [InfoBox("$提示", InfoMessageType.Warning, "@检测数量()>0||字体文件列表.Count == 0")]
    [InfoBox("$提示", InfoMessageType.Info, "@数量==0&&字体文件列表.Count > 0")]

    [BoxGroup("窗口", showLabel: false), HorizontalGroup("窗口/1"), Button(ButtonHeight =50,Icon = SdfIconType.Tools), ShowInInspector, ShowIf("@字体文件列表.Count > 0")] void 配置所有()
    {
        逐个配置(true);
    }
    [BoxGroup("窗口", showLabel: false), HorizontalGroup("窗口/1"), Button(ButtonHeight =50,Icon = SdfIconType.Trash), ShowInInspector, ShowIf("@字体文件列表.Count > 0")] void 清除配置()
    {
        逐个配置(false);
    }

    [TableList, ShowInInspector] public List<字体文件> 字体文件列表 = new List<字体文件>();
    int 检测数量()
    {

        if(字体文件列表.Count == 0)
        {
            提示 = "请刷新列表";
            return 0;
        }
        else
        {
            数量 = 0;
            string 名称 = "";
            foreach (var a in 字体文件列表)
            {
                if (a.配置 == false)
                {
                    数量++;
                    名称 = 名称 + " " + a.名称;
                }
            }
            if (数量 > 0)
            {
                提示 = $"有<color=red> {数量} </color>个字体文件未配置或显示错误。{名称}";
            }
            else
            {
                提示 = $"字体文件全局已配置";
            }
            return 数量;
        }
     
    }
    void 逐个配置(bool 配置)
    {
        foreach (var 字体文件 in 字体文件列表)
        {
            字体文件.修改文件配置(true, 配置);
        }
    }

    
}
#endregion
#endif
#endregion

public class FontSetting: MonoBehaviour{}



#endif

